00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "qs_config.h"
00049 #include "fp20_iqsutil.h"
00050 #include "fp20_mps.h"
00051 #include "fp20_rawlp.h"
00052 #include "fp20_lpdata.h"
00053
00054
00055 static int TRACE = 0;
00056
00057 const char *fp20_ILLmps_section_name[ILL_MPS_N_SECTIONS + 2] = {
00058 "NAME", "OBJSENSE", "OBJNAME", "ROWS", "COLUMNS",
00059 "RHS", "RANGES", "BOUNDS", "REFROW", "ENDATA",
00060 NULL
00061 };
00062
00063 static const char *fp20_mps_bound_name[] = {
00064 "LO", "UP", "FX", "FR", "MI", "PL", "BV", "UI", "LI", NULL
00065 };
00066
00067
00068
00069
00070 static int fp20_read_mps_section (
00071 fp20_ILLread_mps_state * state,
00072 fp20_rawlpdata * lp);
00073
00074 static int fp20_read_mps_name (
00075 fp20_ILLread_mps_state * state,
00076 fp20_rawlpdata * lp);
00077 static int fp20_read_mps_refrow (
00078 fp20_ILLread_mps_state * state,
00079 fp20_rawlpdata * lp);
00080 static int fp20_read_mps_objnamesense (
00081 ILLmps_section sec,
00082 fp20_ILLread_mps_state * state,
00083 fp20_rawlpdata * lp);
00084 static int fp20_read_mps_objname (
00085 fp20_ILLread_mps_state * state);
00086 static int fp20_read_mps_objsense (
00087 fp20_ILLread_mps_state * state,
00088 fp20_rawlpdata * lp);
00089
00090 static int fp20_read_mps_line_in_section (
00091 fp20_ILLread_mps_state * state,
00092 fp20_rawlpdata * lp);
00093
00094
00095 static int fp20_add_row (
00096 fp20_ILLread_mps_state * state,
00097 fp20_rawlpdata * lp);
00098 static int fp20_add_col (
00099 fp20_ILLread_mps_state * state,
00100 fp20_rawlpdata * lp);
00101 static int fp20_add_rhs (
00102 fp20_ILLread_mps_state * state,
00103 fp20_rawlpdata * lp);
00104 static int fp20_add_ranges (
00105 fp20_ILLread_mps_state * state,
00106 fp20_rawlpdata * lp);
00107 static int fp20_add_bounds (
00108 fp20_ILLread_mps_state * state,
00109 fp20_rawlpdata * lp);
00110
00111 static int fp20_mps_read_marker_line (
00112 fp20_ILLread_mps_state * state,
00113 fp20_rawlpdata * lp);
00114 static int fp20_is_marker_line (
00115 fp20_ILLread_mps_state * state);
00116 static int fp20_mps_read_col_line (
00117 fp20_ILLread_mps_state * state,
00118 fp20_rawlpdata * lp);
00119
00120 static int fp20_mps_fill_in (
00121 fp20_rawlpdata * lp,
00122 const char *obj);
00123
00124
00125 static void fp20_mps_set_bound (
00126 fp20_rawlpdata * lp,
00127 fp20_ILLread_mps_state * state,
00128 int colind,
00129 const char *bndtype,
00130 EGfp20_t bnd);
00131
00132 int fp20_ILLread_mps (
00133 fp20_qsline_reader * file,
00134 const char *f,
00135 fp20_rawlpdata * lp)
00136 {
00137 int rval = 0;
00138 int end = 0;
00139 fp20_ILLread_mps_state state;
00140
00141 ILL_IFTRACE ("\tread_mps\n");
00142 if (ILLsymboltab_create (&lp->rowtab, 100) ||
00143 ILLsymboltab_create (&lp->coltab, 100))
00144 {
00145 rval = 1;
00146 }
00147 else
00148 {
00149 rval = fp20_ILLmps_state_init (&state, file, f);
00150 }
00151 if (rval != 0)
00152 {
00153 goto CLEANUP;
00154 }
00155
00156 while (fp20_ILLmps_next_line (&state) == 0)
00157 {
00158 if (fp20_ILLmps_empty_key (&state))
00159 {
00160 if (fp20_read_mps_line_in_section (&state, lp) != 0)
00161 {
00162 rval++;
00163 }
00164 }
00165 else
00166 {
00167
00168 if (!strcmp (state.key, fp20_ILLmps_section_name[ILL_MPS_ENDATA]))
00169 {
00170 end = 1;
00171 break;
00172 }
00173 if (fp20_read_mps_section (&state, lp) != 0)
00174 {
00175 rval++;
00176 }
00177 }
00178 if (rval == 50)
00179 {
00180 (void) fp20_ILLmps_error (&state, "Too many errors.\n");
00181 }
00182 }
00183
00184 if (!end)
00185 {
00186 fp20_ILLmps_warn (&state, "Missing ENDATA.");
00187 }
00188 if (!fp20_ILLmps_next_line (&state))
00189 {
00190 fp20_ILLmps_warn (&state, "Ignoring text after ENDATA.");
00191 }
00192 if (rval == 0)
00193 {
00194 rval = fp20_mps_fill_in (lp, state.obj);
00195 }
00196
00197 CLEANUP:
00198 ILL_RESULT (rval, "read_mps");
00199 }
00200
00201 static int fp20_check_section_order (
00202 fp20_ILLread_mps_state * state,
00203 int sec)
00204 {
00205 switch (sec)
00206 {
00207 case ILL_MPS_REFROW:
00208 if (state->section[ILL_MPS_ROWS] == 1)
00209 {
00210 return fp20_ILLmps_error (state, "%s section after ROWS section.\n",
00211 fp20_ILLmps_section_name[sec]);
00212 }
00213 break;
00214
00215 case ILL_MPS_COLS:
00216 case ILL_MPS_RHS:
00217 case ILL_MPS_RANGES:
00218 if (state->section[ILL_MPS_ROWS] == 0)
00219 {
00220 return fp20_ILLmps_error (state, "%s section before ROWS section.\n",
00221 fp20_ILLmps_section_name[sec]);
00222 };
00223 break;
00224
00225 case ILL_MPS_BOUNDS:
00226 if (state->section[ILL_MPS_COLS] == 0)
00227 {
00228 return fp20_ILLmps_error (state, "%s section before COLUMNS section.\n",
00229 fp20_ILLmps_section_name[sec]);
00230 }
00231 break;
00232 }
00233 return 0;
00234 }
00235
00236 static int fp20_read_mps_section (
00237 fp20_ILLread_mps_state * state,
00238 fp20_rawlpdata * lp)
00239 {
00240 int sec;
00241 int rval = 0, r;
00242
00243 ILL_FAILtrue (fp20_ILLmps_empty_key (state), "must have a key on this line");
00244
00245 sec = fp20_ILLutil_index (fp20_ILLmps_section_name, state->key);
00246 if (sec < 0)
00247 {
00248 return fp20_ILLmps_error (state, "\"%s\" is not a key.\n", state->key);
00249 }
00250 rval = fp20_ILLmps_set_section (state, sec);
00251
00252 state->active = ILL_MPS_NONE;
00253 rval = rval || fp20_check_section_order (state, sec);
00254 switch (sec)
00255 {
00256 case ILL_MPS_COLS:
00257 case ILL_MPS_ROWS:
00258 state->active = sec;
00259 break;
00260
00261 case ILL_MPS_NAME:
00262 if (rval == 0)
00263 {
00264 rval = fp20_read_mps_name (state, lp);
00265 }
00266 break;
00267
00268 case ILL_MPS_RHS:
00269 if (rval == 0)
00270 {
00271 rval = fp20_ILLraw_init_rhs (lp);
00272 }
00273 state->active = ILL_MPS_RHS;
00274 break;
00275
00276 case ILL_MPS_RANGES:
00277 if (rval == 0)
00278 {
00279 rval = fp20_ILLraw_init_ranges (lp);
00280 }
00281 state->active = ILL_MPS_RANGES;
00282 break;
00283
00284 case ILL_MPS_BOUNDS:
00285 if (rval == 0)
00286 {
00287 rval = fp20_ILLraw_init_bounds (lp);
00288 }
00289 state->active = ILL_MPS_BOUNDS;
00290 break;
00291
00292 case ILL_MPS_OBJNAME:
00293 case ILL_MPS_OBJSENSE:
00294 r = fp20_read_mps_objnamesense (sec, state, lp);
00295 rval = r || rval;
00296 break;
00297
00298 case ILL_MPS_REFROW:
00299 r = fp20_read_mps_refrow (state, lp);
00300 rval = r || rval;
00301 break;
00302
00303 default:
00304 ILL_REPRT ("should never get here");
00305 goto CLEANUP;
00306 }
00307 CLEANUP:
00308 ILL_RESULT (rval, "fp20_read_mps_section");
00309 }
00310
00311 static int fp20_read_mps_name (
00312 fp20_ILLread_mps_state * state,
00313 fp20_rawlpdata * lp)
00314 {
00315 int rval = 0;
00316
00317 if (fp20_ILLmps_empty_field (state))
00318 {
00319 fp20_ILLmps_warn (state, "Blank NAME.");
00320 }
00321 else
00322 {
00323 fp20_ILL_UTIL_STR (lp->name, state->field);
00324 }
00325 CLEANUP:
00326 ILL_RESULT (rval, "fp20_read_mps_name");
00327 }
00328
00329 static int fp20_read_mps_refrow (
00330 fp20_ILLread_mps_state * state,
00331 fp20_rawlpdata * lp)
00332 {
00333 int rval = 0;
00334
00335 rval = fp20_ILLmps_next_line (state);
00336 if (state->section[ILL_MPS_REFROW] > 1)
00337 {
00338
00339
00340 return 0;
00341 }
00342 if (fp20_ILLmps_empty_key (state) && !fp20_ILLmps_empty_field (state))
00343 {
00344 fp20_ILL_UTIL_STR (lp->refrow, state->field);
00345 return 0;
00346 }
00347 else
00348 {
00349 return fp20_ILLmps_error (state, "Bad row name in REFROW section.\n");
00350 }
00351 CLEANUP:
00352 ILL_RETURN (rval, "fp20_read_mps_refrow");
00353 }
00354
00355 static int fp20_read_mps_objnamesense (
00356 ILLmps_section sec,
00357 fp20_ILLread_mps_state * state,
00358 fp20_rawlpdata * lp)
00359 {
00360 if (state->section[sec] > 1)
00361 {
00362
00363 (void) fp20_ILLmps_next_line (state);
00364 return 0;
00365 }
00366 if (fp20_ILLmps_next_line (state) != 0)
00367 {
00368 return fp20_ILLmps_error (state, "Missing %s line at end of file.\n",
00369 fp20_ILLmps_section_name[sec]);
00370 }
00371 if ((!fp20_ILLmps_empty_key (state)) || fp20_ILLmps_empty_field (state))
00372 {
00373 (void) fp20_ILLmps_error (state, "Bad %s in %s record.\n",
00374 ((sec == ILL_MPS_OBJNAME) ? "row name"
00375 : "objective sense"), fp20_ILLmps_section_name[sec]);
00376 if (!fp20_ILLmps_empty_key (state))
00377 {
00378 (void) fp20_read_mps_section (state, lp);
00379 }
00380 return 1;
00381 }
00382 if (sec == ILL_MPS_OBJNAME)
00383 {
00384 if (fp20_read_mps_objname (state))
00385 {
00386 return 1;
00387 }
00388 }
00389 else
00390 {
00391 if (fp20_read_mps_objsense (state, lp) != 0)
00392 {
00393 return 1;
00394 }
00395 }
00396 return 0;
00397 }
00398
00399 static int fp20_read_mps_objsense (
00400 fp20_ILLread_mps_state * state,
00401 fp20_rawlpdata * lp)
00402 {
00403 int rval = 0;
00404 char *objsense = state->field;
00405
00406 ILL_FAILfalse (state->section[ILL_MPS_OBJSENSE] == 1, "should never happen");
00407 if (!strcmp (objsense, "MAX") ||
00408 !strcmp (objsense, "Max") ||
00409 !strcmp (objsense, "max") ||
00410 !strcmp (objsense, "MAXIMIZE") ||
00411 !strcmp (objsense, "Maximize") || !strcmp (objsense, "maximize"))
00412 {
00413 lp->objsense = fp20_ILL_MAX;
00414 }
00415 else if (!strcmp (objsense, "MIN") ||
00416 !strcmp (objsense, "Min") ||
00417 !strcmp (objsense, "min") ||
00418 !strcmp (objsense, "MINIMIZE") ||
00419 !strcmp (objsense, "Minimize") || !strcmp (objsense, "minimize"))
00420 {
00421 lp->objsense = fp20_ILL_MIN;
00422 }
00423 else
00424 {
00425 return fp20_ILLmps_error (state, "\"%s\" is no OBJSENSE.\n", objsense);
00426 }
00427 CLEANUP:
00428 ILL_RESULT (rval, "fp20_read_mps_objsense");
00429 }
00430
00431 static int fp20_read_mps_objname (
00432 fp20_ILLread_mps_state * state)
00433 {
00434 int rval = 0;
00435
00436 ILL_FAILfalse (state->section[ILL_MPS_OBJNAME] == 1, "should never happen");
00437 fp20_ILL_UTIL_STR (state->obj, state->field);
00438 CLEANUP:
00439 ILL_RETURN (rval, "fp20_read_mps_objname");
00440 }
00441
00442 static int fp20_read_mps_line_in_section (
00443 fp20_ILLread_mps_state * state,
00444 fp20_rawlpdata * lp)
00445 {
00446 int rval = 0;
00447
00448 ILL_FAILtrue (!fp20_ILLmps_empty_key (state) || fp20_ILLmps_empty_field (state),
00449 "no key but at least one field on state->line");
00450
00451 if (state->active == ILL_MPS_NONE)
00452 {
00453 return fp20_ILLmps_error (state, "Line is in no section.\n");
00454 }
00455 else
00456 {
00457 if (state->section[state->active] == 1)
00458 {
00459 switch (state->active)
00460 {
00461 case ILL_MPS_ROWS:
00462 rval = fp20_add_row (state, lp);
00463 break;
00464 case ILL_MPS_COLS:
00465 rval = fp20_add_col (state, lp);
00466 break;
00467 case ILL_MPS_RHS:
00468 rval = fp20_add_rhs (state, lp);
00469 break;
00470 case ILL_MPS_RANGES:
00471 rval = fp20_add_ranges (state, lp);
00472 break;
00473 case ILL_MPS_BOUNDS:
00474 rval = fp20_add_bounds (state, lp);
00475 break;
00476 default:
00477 ILL_REPRT ("should never get here");
00478 ILL_CLEANUP;
00479 }
00480 if (rval == 0)
00481 {
00482
00483 fp20_ILLmps_check_end_of_line (state);
00484 }
00485 }
00486 }
00487 CLEANUP:
00488 ILL_RESULT (rval, "fp20_read_mps_line_in_section");
00489 }
00490
00491 static int fp20_add_row (
00492 fp20_ILLread_mps_state * state,
00493 fp20_rawlpdata * lp)
00494 {
00495 int ind, hit, rval = 0;
00496 char sense;
00497
00498 ILL_FAILtrue (!fp20_ILLmps_empty_key (state) || fp20_ILLmps_empty_field (state),
00499 "no key but at least one field on state->line");
00500
00501
00502 if (state->field[1] == '\0')
00503 {
00504 sense = state->field[0];
00505 if (sense != 'L' && sense != 'G' && sense != 'E' && sense != 'N')
00506 {
00507 return fp20_ILLmps_error (state,
00508 "Unknown rowsense '%c' in ROWS record.\n", sense);
00509 }
00510 if (fp20_ILLmps_next_field (state) == 0)
00511 {
00512 hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &ind);
00513 if (!hit)
00514 {
00515 rval = fp20_ILLmps_error (state,
00516 "Repeated row definition for \"%s\".\n",
00517 state->field);
00518 }
00519 else
00520 {
00521 rval = fp20_ILLraw_add_row (lp, state->field, sense, fp20_zeroLpNum);
00522 }
00523 }
00524 else
00525 {
00526 rval = fp20_ILLmps_error (state, "Missing rowname in ROWS record.\n");
00527 }
00528 }
00529 else
00530 {
00531 rval = fp20_ILLmps_error (state, "Unknown rowsense '%s' in ROWS record.\n",
00532 state->field);
00533 }
00534 CLEANUP:
00535 ILL_RESULT (rval, "fp20_add_row");
00536 }
00537
00538 static int fp20_add_col (
00539 fp20_ILLread_mps_state * state,
00540 fp20_rawlpdata * lp)
00541 {
00542 int rval = 0;
00543
00544 ILL_FAILtrue (!fp20_ILLmps_empty_key (state) || fp20_ILLmps_empty_field (state),
00545 "no key but at least one field on state->line");
00546
00547 if (fp20_is_marker_line (state))
00548 {
00549 return fp20_mps_read_marker_line (state, lp);
00550 }
00551 else
00552 {
00553 return fp20_mps_read_col_line (state, lp);
00554 }
00555 CLEANUP:
00556 ILL_RETURN (rval, "fp20_add_col");
00557 }
00558
00559 static int fp20_mps_read_col_line (
00560 fp20_ILLread_mps_state * state,
00561 fp20_rawlpdata * lp)
00562 {
00563 int hit, colind, rowind, rval = 0, more, ind;
00564 EGfp20_t ncoef;
00565
00566 fp20_EGlpNumInitVar (ncoef);
00567
00568 ILL_FAILtrue (!fp20_ILLmps_empty_key (state) || fp20_ILLmps_empty_field (state),
00569 "no key but at least one field on state->line");
00570
00571 hit = ILLsymboltab_lookup (&lp->coltab, state->field, &colind);
00572 if (hit)
00573 {
00574 rval = fp20_ILLraw_add_col (lp, state->field, state->intvar);
00575 ILL_CLEANUP_IF (rval);
00576 colind = lp->ncols - 1;
00577 }
00578 else
00579 {
00580 if (state->intvar)
00581 {
00582
00583 lp->intmarker[colind] = 1;
00584 }
00585 }
00586 #ifndef NDEBUG
00587 hit = ILLsymboltab_lookup (&lp->coltab, state->field, &ind);
00588 ILL_FAILfalse (colind == ind, "colind should be index of state->field");
00589 #endif
00590 if (state->sosvar == 1)
00591 {
00592 if (fp20_ILLraw_is_mem_other_sos (lp, colind))
00593 {
00594 rval = fp20_ILLmps_error (state,
00595 "\"%s\" is a member of SOS set #%d.\n",
00596 fp20_ILLraw_colname (lp, colind),
00597 lp->is_sos_member[colind] + 1);
00598 }
00599 else
00600 {
00601 rval = fp20_ILLraw_add_sos_member (lp, colind);
00602 }
00603 ILL_CLEANUP_IF (rval);
00604 }
00605
00606 more = (fp20_ILLmps_next_field (state) == 0);
00607 if (!more)
00608 {
00609 return fp20_ILLmps_error (state, "Missing fields in COLUMNS record.\n");
00610 }
00611 for (more = 1; more; more = (fp20_ILLmps_next_field (state) == 0))
00612 {
00613 hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind);
00614 if (hit)
00615 {
00616 return fp20_ILLmps_error (state, "\"%s\" is not a row name.\n", state->field);
00617 }
00618 if (fp20_ILLmps_next_coef (state, &ncoef) != 0)
00619 {
00620 return fp20_ILLmps_error (state,
00621 "Missing/Bad coefficient in COLUMNS record.\n");
00622 }
00623 rval = fp20_ILLraw_add_col_coef (lp, colind, rowind, ncoef);
00624 }
00625 CLEANUP:
00626 fp20_EGlpNumClearVar (ncoef);
00627 ILL_RESULT (rval, "fp20_mps_read_col_line");
00628 }
00629
00630 static int fp20_is_marker_line (
00631 fp20_ILLread_mps_state * state)
00632 {
00633 const char *field = state->line;
00634
00635 while ((field = fp20_ILLutil_strchr (field, '\'')))
00636 {
00637 if (strncmp (field, "'MARKER'", (size_t) 8) == 0)
00638 {
00639 return 1;
00640 }
00641 while ((!fp20_ILL_ISBLANK (field)) && (*field != '\0'))
00642 {
00643 field++;
00644 }
00645 }
00646 return 0;
00647 }
00648
00649 static int fp20_mps_read_marker_line (
00650 fp20_ILLread_mps_state * state,
00651 fp20_rawlpdata * lp)
00652 {
00653 int rval = 0;
00654 int sos_type = fp20_ILL_SOS_TYPE1;
00655 int sos_line = 0;
00656 int cur_sos_mode = state->sosvar;
00657
00658 if (strcmp (state->field, "S2") == 0)
00659 {
00660 sos_type = fp20_ILL_SOS_TYPE2;
00661 sos_line = 1;
00662 }
00663 else if (strcmp (state->field, "S1") == 0)
00664 {
00665 sos_line = 1;
00666 }
00667 if (sos_line)
00668 {
00669 rval = fp20_ILLmps_next_field (state);
00670 }
00671 rval = rval || fp20_ILLmps_next_field (state);
00672 if (strcmp (state->field, "'MARKER'"))
00673 {
00674 return fp20_ILLmps_error (state, "Bad 'MARKER' line.\n");
00675 }
00676 if (fp20_ILLmps_next_field (state))
00677 {
00678 return fp20_ILLmps_error (state, "Missing field on 'MARKER' line.\n");
00679 }
00680 rval = fp20_ILLmps_int_sos_mode (state);
00681 if (rval == 0)
00682 {
00683 if (cur_sos_mode != state->sosvar)
00684 {
00685 if (state->sosvar)
00686 {
00687
00688 rval = fp20_ILLraw_add_sos (lp, sos_type);
00689 }
00690 }
00691 }
00692 ILL_RESULT (rval, "fp20_mps_read_marker_line");
00693 }
00694
00695 static int fp20_add_rhs (
00696 fp20_ILLread_mps_state * state,
00697 fp20_rawlpdata * lp)
00698 {
00699 int rowind, more_fields, skip;
00700 const char *rhsname;
00701 EGfp20_t rhs;
00702
00703 fp20_EGlpNumInitVar (rhs);
00704
00705 rhsname = fp20_ILLmps_possibly_blank_name (state->field, state, &lp->rowtab);
00706 if (fp20_ILLraw_set_rhs_name (lp, rhsname, &skip))
00707 {
00708 fp20_ILLmps_error (state, "Could not add right hand side.\n");
00709 }
00710
00711 if (skip)
00712 {
00713 fp20_ILLmps_set_end_of_line (state);
00714 }
00715 else
00716 {
00717 if (strcmp (rhsname, " "))
00718 {
00719
00720 if (fp20_ILLmps_next_field (state))
00721 {
00722 return fp20_ILLmps_error (state, "Missing row name in RHS record.\n");
00723 }
00724 }
00725 for (more_fields = 1; more_fields; more_fields = !fp20_ILLmps_next_field (state))
00726 {
00727 if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind))
00728 {
00729 return fp20_ILLmps_error (state, "\"%s\" is not a row name.\n",
00730 state->field);
00731 }
00732 if (fp20_ILLmps_next_coef (state, &rhs))
00733 {
00734 return fp20_ILLmps_error (state, "Missing/Bad coefficient in RHS record.\n");
00735 }
00736 if (lp->rhsind[rowind])
00737 {
00738 return fp20_ILLmps_error (state, "Two rhs values for row \"%s\".\n",
00739 state->field);
00740 }
00741 else
00742 {
00743 if (lp->rowsense[rowind] == 'N')
00744 {
00745 fp20_ILLmps_warn (state,
00746 "Ignoring right hand side for N-row \"%s\".",
00747 fp20_ILLraw_rowname (lp, rowind));
00748 }
00749 else
00750 {
00751 fp20_EGlpNumCopy (lp->rhs[rowind], rhs);
00752 lp->rhsind[rowind] = 1;
00753 }
00754 }
00755 }
00756 }
00757 fp20_EGlpNumClearVar (rhs);
00758 return 0;
00759 }
00760
00761 static int fp20_add_bounds (
00762 fp20_ILLread_mps_state * state,
00763 fp20_rawlpdata * lp)
00764 {
00765 char bndtype[3];
00766 const char *bounds_name;
00767 int colind, skip, rval = 0;
00768 EGfp20_t bnd;
00769
00770 fp20_EGlpNumInitVar (bnd);
00771
00772 ILL_FAILtrue (!fp20_ILLmps_empty_key (state) || fp20_ILLmps_empty_field (state),
00773 "no key but at least one field on state->line");
00774
00775 if (fp20_ILLutil_index (fp20_mps_bound_name, state->field) < 0)
00776 {
00777 return fp20_ILLmps_error (state, "\"%s\" is not a BOUNDS type.\n", state->field);
00778 }
00779 strcpy (bndtype, state->field);
00780
00781 if (fp20_ILLmps_next_field (state) != 0)
00782 {
00783 return fp20_ILLmps_error (state,
00784 "No bounds/column identifier in BOUNDS record.\n");
00785 }
00786
00787 bounds_name = fp20_ILLmps_possibly_blank_name (state->field, state, &lp->coltab);
00788 if (bounds_name == NULL)
00789 {
00790 return 1;
00791 }
00792 if (fp20_ILLraw_set_bounds_name (lp, bounds_name, &skip))
00793 {
00794 return 1;
00795 }
00796 if (skip)
00797 {
00798 fp20_ILLmps_set_end_of_line (state);
00799 }
00800 else
00801 {
00802 if (strcmp (bounds_name, " "))
00803 {
00804
00805 if (fp20_ILLmps_next_field (state))
00806 {
00807 return fp20_ILLmps_error (state, "Missing column field in BOUNDS record.\n");
00808 }
00809 }
00810 if (ILLsymboltab_lookup (&lp->coltab, state->field, &colind))
00811 {
00812 return fp20_ILLmps_error (state, "\"%s\" is not a column name.\n",
00813 state->field);
00814 }
00815 fp20_EGlpNumZero (bnd);
00816 if (strcmp (bndtype, "FR") && strcmp (bndtype, "BV") &&
00817 strcmp (bndtype, "MI") && strcmp (bndtype, "PL"))
00818 {
00819
00820 if (fp20_ILLmps_next_bound (state, &bnd))
00821 {
00822 return fp20_ILLmps_error (state,
00823 "Missing/Bad bound field in BOUNDS record.\n");
00824 }
00825 }
00826 fp20_mps_set_bound (lp, state, colind, bndtype, bnd);
00827 }
00828 CLEANUP:
00829 fp20_EGlpNumClearVar (bnd);
00830 ILL_RESULT (rval, "fp20_add_bounds");
00831 }
00832
00833 static void fp20_mps_set_bound (
00834 fp20_rawlpdata * lp,
00835 fp20_ILLread_mps_state * state,
00836 int colind,
00837 const char *bndtype,
00838 EGfp20_t bnd)
00839 {
00840 const char *msg = NULL;
00841
00842 if (!strcmp (bndtype, "LO"))
00843 {
00844 msg = fp20_ILLraw_set_lowerBound (lp, colind, bnd);
00845 }
00846 else if (!strcmp (bndtype, "UP"))
00847 {
00848 msg = fp20_ILLraw_set_upperBound (lp, colind, bnd);
00849 }
00850 else if (!strcmp (bndtype, "FX"))
00851 {
00852 msg = fp20_ILLraw_set_fixedBound (lp, colind, bnd);
00853 }
00854 else if (!strcmp (bndtype, "FR"))
00855 {
00856 msg = fp20_ILLraw_set_unbound (lp, colind);
00857 }
00858 else if (!strcmp (bndtype, "BV"))
00859 {
00860 msg = fp20_ILLraw_set_binaryBound (lp, colind);
00861 if (msg == NULL)
00862 {
00863 lp->intmarker[colind] = 1;
00864 }
00865 }
00866 else if (!strcmp (bndtype, "UI"))
00867 {
00868 msg = fp20_ILLraw_set_upperBound (lp, colind, bnd);
00869 if (msg == NULL)
00870 {
00871 lp->intmarker[colind] = 1;
00872 }
00873 }
00874 else if (!strcmp (bndtype, "LI"))
00875 {
00876 msg = fp20_ILLraw_set_lowerBound (lp, colind, bnd);
00877 if (msg == NULL)
00878 {
00879 lp->intmarker[colind] = 1;
00880 }
00881 }
00882 else if (!strcmp (bndtype, "MI"))
00883 {
00884 msg = fp20_ILLraw_set_lowerBound (lp, colind, fp20_ILL_MINDOUBLE);
00885 }
00886 else if (!strcmp (bndtype, "PL"))
00887 {
00888 msg = fp20_ILLraw_set_upperBound (lp, colind, fp20_ILL_MAXDOUBLE);
00889 }
00890 else
00891 {
00892 ILL_REPRT ("should never get here");
00893 ILL_CLEANUP;
00894 }
00895 fp20_ILLmps_warn (state, msg);
00896 CLEANUP:
00897 return;
00898 }
00899
00900 static int fp20_add_ranges (
00901 fp20_ILLread_mps_state * state,
00902 fp20_rawlpdata * lp)
00903 {
00904 const char *rangesname;
00905 int skip, more_fields, rowind;
00906 EGfp20_t ntmp;
00907
00908 fp20_EGlpNumInitVar (ntmp);
00909
00910 rangesname = fp20_ILLmps_possibly_blank_name (state->field, state, &lp->rowtab);
00911 if (fp20_ILLraw_set_ranges_name (lp, rangesname, &skip))
00912 {
00913 return fp20_ILLmps_error (state, "Could not add range.\n");
00914 }
00915 if (skip)
00916 {
00917 fp20_ILLmps_set_end_of_line (state);
00918 }
00919 else
00920 {
00921 if (strcmp (rangesname, " "))
00922 {
00923
00924 if (fp20_ILLmps_next_field (state))
00925 {
00926 return fp20_ILLmps_error (state, "Missing row name in RANGES record.");
00927 }
00928 }
00929 for (more_fields = 1; more_fields; more_fields = !fp20_ILLmps_next_field (state))
00930 {
00931 if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind))
00932 {
00933 return fp20_ILLmps_error (state, "\"%s\" is not a row name.\n",
00934 state->field);
00935 }
00936 if (fp20_ILLmps_next_coef (state, &ntmp))
00937 {
00938 return fp20_ILLmps_error (state,
00939 "Missing/Bad coefficient in RANGES record.\n");
00940 }
00941 if (lp->rangesind[rowind])
00942 {
00943 fp20_ILLmps_warn (state, "Ignoring second RANGE value %s \"%s\".",
00944 "for row", fp20_ILLraw_rowname (lp, rowind));
00945 }
00946 else
00947 {
00948 if (lp->rowsense[rowind] != 'N')
00949 {
00950 if (fp20_ILLraw_add_ranges_coef (lp, rowind, ntmp))
00951 return 1;
00952 }
00953 else
00954 {
00955 fp20_ILLmps_warn (state, "Ignoring RANGE value for N-row \"%s\".",
00956 fp20_ILLraw_rowname (lp, rowind));
00957 }
00958 }
00959 }
00960 }
00961 fp20_EGlpNumClearVar (ntmp);
00962 return 0;
00963 }
00964
00965
00966 static int fp20_mps_fill_in (
00967 fp20_rawlpdata * lp,
00968 const char *obj)
00969 {
00970 int i, hit, rval = 0;
00971
00972
00973 if (obj)
00974 {
00975 hit = ILLsymboltab_lookup (&lp->rowtab, obj, &lp->objindex);
00976 if (hit)
00977 {
00978 return fp20_ILLdata_error (lp->error_collector,
00979 "Bad objective name \"%s\".\n", obj);
00980 }
00981 else if (lp->rowsense[lp->objindex] != 'N')
00982 {
00983 fp20_ILLdata_warn (lp->error_collector,
00984 "Making objective row \"%s\" a N-row.", obj);
00985 }
00986 lp->rowsense[lp->objindex] = 'N';
00987 }
00988 else
00989 {
00990 for (i = 0; i < lp->nrows; i++)
00991 {
00992 if (lp->rowsense[i] == 'N')
00993 {
00994 lp->objindex = i;
00995 break;
00996 }
00997 }
00998 if (i == lp->nrows)
00999 {
01000 return fp20_ILLdata_error (lp->error_collector,
01001 "No N-row in lp definition.\n");
01002 }
01003 }
01004
01005 if (lp->ncols > 0)
01006 {
01007 rval = fp20_ILLraw_fill_in_bounds (lp);
01008 }
01009
01010
01011 if (lp->refrow)
01012 {
01013
01014 EGfp20_t weight;
01015 fp20_colptr *cp;
01016
01017 fp20_EGlpNumInitVar (weight);
01018
01019 hit = ILLsymboltab_lookup (&lp->rowtab, lp->refrow, &lp->refrowind);
01020 if (hit)
01021 {
01022 return fp20_ILLdata_error (lp->error_collector,
01023 "REFROW \"%s\" is not a row name.\n", lp->refrow);
01024 }
01025 for (i = 0; i < lp->nsos_member; i++)
01026 {
01027 for (cp = lp->cols[lp->sos_col[i]]; cp != NULL; cp = cp->next)
01028 {
01029 if (cp->this_val == lp->refrowind)
01030 break;
01031 }
01032 if ((cp != NULL) && fp20_EGlpNumIsNeqqZero (cp->coef))
01033 {
01034 fp20_EGlpNumCopy (weight, cp->coef);
01035 }
01036 else
01037 {
01038 fp20_ILLdata_warn (lp->error_collector,
01039 "\"%s\" has 0.0 coefficient in REFROW \"%s\".",
01040 fp20_ILLraw_colname (lp, lp->sos_col[i]), lp->refrow);
01041 fp20_EGlpNumZero (weight);
01042 }
01043 fp20_EGlpNumCopy (lp->sos_weight[i], weight);
01044 }
01045 fp20_EGlpNumClearVar (weight);
01046 }
01047 else
01048 {
01049
01050 int si, w;
01051 fp20_sosptr *set;
01052
01053 for (si = 0; si < lp->nsos; si++)
01054 {
01055 set = lp->sos_set + si;
01056 w = 1;
01057 for (i = set->first; i < set->first + set->nelem; i++)
01058 {
01059 fp20_EGlpNumSet (lp->sos_weight[i], (double) w);
01060 w++;
01061 }
01062 }
01063 }
01064 ILL_IFTRACE ("bound %lf <= x1 <= %lf\n", fp20_EGlpNumToLf (lp->lower[0]),
01065 fp20_EGlpNumToLf (lp->upper[0]));
01066 ILL_IFTRACE ("MAXDOUBLE %lf MINDOUBLE %lf\n", fp20_EGlpNumToLf (fp20_ILL_MAXDOUBLE),
01067 fp20_EGlpNumToLf (fp20_ILL_MINDOUBLE));
01068 ILL_RESULT (rval, "fp20_mps_fill_in");
01069 }
01070
01071
01072
01073
01074
01075 static int fp20_mps_write_col (
01076 int i,
01077 int iorig,
01078 char *colname,
01079 fp20_ILLlpdata * lp,
01080 char **rownames,
01081 int intmode,
01082 char *objname);
01083
01084 int fp20_ILLwrite_mps (
01085 fp20_ILLlpdata * lp,
01086 fp20_qserror_collector * collector)
01087 {
01088 int rval = 0;
01089 int marker = 0;
01090 int intmode = 0;
01091 int i, ri, set, el, empty, prtLower, prtUpper;
01092 char **colnames = (char **) NULL;
01093 char **rownames = (char **) NULL;
01094 fp20_ILLlp_rows lp_rows, *lprows = NULL;
01095 char buf[ILL_namebufsize];
01096 char *objname = NULL;
01097 char *str;
01098
01099 ILL_CHECKnull (lp, "lp must not be null");
01100 ILL_FAILtrue (lp->probname == NULL, "oops should never happen");
01101
01102 ILL_FAILfalse (lp->colnames != NULL, "colnames != NULL");
01103 ILL_FAILfalse (lp->rownames != NULL, "colnames != NULL");
01104 colnames = lp->colnames;
01105 rownames = lp->rownames;
01106
01107 objname = lp->objname;
01108 if (objname == (char *) NULL)
01109 {
01110 strcpy (buf, "obj");
01111 rval = ILLsymboltab_uname (&lp->rowtab, buf, "", NULL);
01112 ILL_CLEANUP_IF (rval);
01113 fp20_ILL_UTIL_STR (objname, buf);
01114 }
01115 fp20_ILLprint_report (lp, "NAME %s\n", lp->probname);
01116 fp20_ILLprint_report (lp, "OBJSENSE\n %s\n",
01117 (lp->objsense == fp20_ILL_MIN) ? "MIN" : "MAX");
01118 fp20_ILLprint_report (lp, "OBJNAME\n %s\n", objname);
01119 if (lp->refrowname)
01120 {
01121 fp20_ILLprint_report (lp, "REFROW\n");
01122 fp20_ILLprint_report (lp, " %s\n", lp->refrowname);
01123 }
01124
01125
01126 fp20_ILLprint_report (lp, "ROWS\n");
01127 fp20_ILLprint_report (lp, " N %s\n", objname);
01128 if (lp->refrowname && (lp->refind == -1))
01129 {
01130 fp20_ILLprint_report (lp, " N %s\n", lp->refrowname);
01131 }
01132
01133 lprows = &lp_rows;
01134 rval = fp20_ILLlp_rows_init (lprows, lp, 0);
01135 ILL_CLEANUP_IF (rval);
01136 for (i = 0; i < lp->nrows; i++)
01137 {
01138 if (lprows->rowcnt[i] == 0)
01139 {
01140 fp20_ILLdata_warn (collector,
01141 "Deleting empty row \"%s\" from constraints.", rownames[i]);
01142 continue;
01143 }
01144 switch (lp->sense[i])
01145 {
01146 case 'G':
01147 fp20_ILLprint_report (lp, " G ");
01148 break;
01149 case 'L':
01150 fp20_ILLprint_report (lp, " L ");
01151 break;
01152 case 'E':
01153 fp20_ILLprint_report (lp, " E ");
01154 break;
01155 case 'R':
01156 fp20_ILLprint_report (lp, " G ");
01157 break;
01158 }
01159 fp20_ILLprint_report (lp, "%s\n", rownames[i]);
01160 }
01161
01162 fp20_ILLprint_report (lp, "COLUMNS\n");
01163 for (set = 0; set < lp->sos.matcols; set++)
01164 {
01165 ILL_FAILtrue (lp->sos_type == NULL, "must have non NULL sos_type");
01166 ILL_FAILtrue (lp->is_sos_mem == NULL, "must have non NULL is_sos_mem");
01167 empty = 1;
01168 for (el = lp->sos.matbeg[set];
01169 el < lp->sos.matbeg[set] + lp->sos.matcnt[set]; el++)
01170 {
01171 if (empty)
01172 {
01173 fp20_ILLprint_report (lp, " %s SOS%dqs 'MARKER' 'SOSORG'\n",
01174 ((lp->sos_type[set] == fp20_ILL_SOS_TYPE1)) ? "S1" : "S2",
01175 marker++);
01176 empty = 0;
01177 }
01178 ri = lp->sos.matind[el];
01179 i = lp->structmap[ri];
01180 intmode = fp20_mps_write_col (i, ri, colnames[ri], lp, rownames,
01181 intmode, objname);
01182 if (lp->refrowname && (lp->refind == -1))
01183 {
01184 fp20_ILLprint_report (lp, " %s %s %g\n",
01185 colnames[ri], lp->refrowname, lp->sos.matval[el]);
01186 }
01187 }
01188 if (!empty)
01189 {
01190 fp20_ILLprint_report (lp, " SOS%dqs 'MARKER' 'SOSEND'\n", marker++);
01191 }
01192 }
01193 for (ri = 0; ri < lp->nstruct; ri++)
01194 {
01195 if (lp->is_sos_mem == (int *) NULL || lp->is_sos_mem[ri] == -1)
01196 {
01197 i = lp->structmap[ri];
01198 intmode = fp20_mps_write_col (i, ri, colnames[ri], lp, rownames,
01199 intmode, objname);
01200 }
01201 }
01202 if (intmode)
01203 {
01204 fp20_ILLprint_report (lp, " MARK%dqs 'MARKER' 'INTEND'\n", lp->nstruct);
01205 }
01206
01207 fp20_ILLprint_report (lp, "RHS\n");
01208 for (i = 0; i < lp->nrows; i++)
01209 {
01210 if ((lprows->rowcnt[i] != 0) && fp20_EGlpNumIsNeqqZero (lp->rhs[i]))
01211 {
01212 str = fp20_EGlpNumGetStr(lp->rhs[i]);
01213 fp20_ILLprint_report (lp, " RHS %s %s\n", rownames[i], str);
01214 EGfree(str);
01215 }
01216 }
01217
01218 if (lp->rangeval)
01219 {
01220 fp20_ILLprint_report (lp, "RANGES\n");
01221 for (i = 0; i < lp->nrows; i++)
01222 {
01223 if ((lprows->rowcnt[i] != 0) && fp20_EGlpNumIsNeqqZero (lp->rangeval[i]))
01224 {
01225 str = fp20_EGlpNumGetStr(lp->rangeval[i]);
01226 fp20_ILLprint_report (lp, " RANGE %s %s\n", rownames[i], str);
01227 EGfree(str);
01228 }
01229 }
01230 }
01231
01232 ri = fp20_ILLraw_first_nondefault_bound (lp);
01233 if (ri != lp->nstruct)
01234 {
01235 fp20_ILLprint_report (lp, "BOUNDS\n");
01236 for (ri = ri; ri < lp->nstruct; ri++)
01237 {
01238 i = lp->structmap[ri];
01239 if (fp20_EGlpNumIsEqqual (lp->lower[i], lp->upper[i]))
01240 {
01241 str = fp20_EGlpNumGetStr(lp->lower[i]);
01242 fp20_ILLprint_report (lp, " FX BOUND %s %s\n", colnames[ri], str);
01243 EGfree(str);
01244 continue;
01245 }
01246 if ((fp20_EGlpNumIsEqqual (lp->lower[i], fp20_ILL_MINDOUBLE)) &&
01247 (fp20_EGlpNumIsEqqual (lp->upper[i], fp20_ILL_MAXDOUBLE)))
01248 {
01249 fp20_ILLprint_report (lp, " FR BOUND %s\n", colnames[ri]);
01250 continue;
01251 }
01252 prtLower = !fp20_ILLraw_default_lower (lp, i);
01253 prtUpper = !fp20_ILLraw_default_upper (lp, i, ri);
01254 if (prtLower)
01255 {
01256 if (fp20_EGlpNumIsEqqual (lp->lower[i], fp20_ILL_MINDOUBLE))
01257 {
01258 fp20_ILLprint_report (lp, " MI BOUND %s\n", colnames[ri]);
01259 }
01260 else
01261 {
01262 str = fp20_EGlpNumGetStr(lp->lower[i]);
01263 fp20_ILLprint_report (lp, " LO BOUND %s %s\n", colnames[ri], str);
01264 EGfree(str);
01265 }
01266 }
01267 if (prtUpper)
01268 {
01269 if (fp20_EGlpNumIsEqqual (lp->upper[i], fp20_ILL_MAXDOUBLE))
01270 {
01271 fp20_ILLprint_report (lp, " PL BOUND %s\n", colnames[ri]);
01272 }
01273 else
01274 {
01275 str = fp20_EGlpNumGetStr(lp->upper[i]);
01276 fp20_ILLprint_report (lp, " UP BOUND %s %s\n", colnames[ri], str);
01277 EGfree(str);
01278 }
01279 }
01280 }
01281 }
01282 fp20_ILLprint_report (lp, "ENDATA\n");
01283
01284 CLEANUP:
01285 fp20_ILLlp_rows_clear (lprows);
01286 if (!lp->colnames)
01287 {
01288 ILLfree_names (colnames, lp->ncols);
01289 }
01290 if (!lp->rownames)
01291 {
01292 ILLfree_names (rownames, lp->nrows);
01293 }
01294 if (objname != lp->objname)
01295 {
01296 ILL_IFFREE (objname, char);
01297 }
01298 ILL_RESULT (rval, "ILLlpdata_mpswrite");
01299 }
01300
01301 static int fp20_mps_write_col (
01302 int i,
01303 int iorig,
01304 char *colname,
01305 fp20_ILLlpdata * lp,
01306 char **rownames,
01307 int intmode,
01308 char *objname)
01309 {
01310 int row, k;
01311 char*str;
01312 fp20_ILLmatrix *A;
01313
01314 A = &lp->A;
01315 if (lp->intmarker && (lp->intmarker[iorig] != intmode))
01316 {
01317 fp20_ILLprint_report (lp, " MARK%dqs 'MARKER' '%s'\n", iorig,
01318 (lp->intmarker[iorig] ? "INTORG" : "INTEND"));
01319 intmode = lp->intmarker[iorig];
01320 }
01321 if (fp20_EGlpNumIsNeqqZero (lp->obj[i]))
01322 {
01323 str = fp20_EGlpNumGetStr(lp->obj[i]);
01324 fp20_ILLprint_report (lp, " %s %s %s\n", colname, objname, str);
01325 EGfree(str);
01326 }
01327 for (k = A->matbeg[i]; k < A->matbeg[i] + A->matcnt[i]; k++)
01328 {
01329 row = A->matind[k];
01330 str = fp20_EGlpNumGetStr(A->matval[k]);
01331 fp20_ILLprint_report (lp, " %s %s %s\n", colname, rownames[row], str);
01332 EGfree(str);
01333 }
01334 return intmode;
01335 }