dbl_mps.c

Go to the documentation of this file.
00001 /****************************************************************************/
00002 /*                                                                          */
00003 /*  This file is part of QSopt_ex.                                          */
00004 /*                                                                          */
00005 /*  (c) Copyright 2006 by David Applegate, William Cook, Sanjeeb Dash,      */
00006 /*  and Daniel Espinoza                                                     */
00007 /*                                                                          */
00008 /*  Sanjeeb Dash ownership of copyright in QSopt_ex is derived from his     */
00009 /*  copyright in QSopt.                                                     */
00010 /*                                                                          */
00011 /*  This code may be used under the terms of the GNU General Public License */
00012 /*  (Version 2.1 or later) as published by the Free Software Foundation.    */
00013 /*                                                                          */
00014 /*  Alternatively, use is granted for research purposes only.               */
00015 /*                                                                          */
00016 /*  It is your choice of which of these two licenses you are operating      */
00017 /*  under.                                                                  */
00018 /*                                                                          */
00019 /*  We make no guarantees about the correctness or usefulness of this code. */
00020 /*                                                                          */
00021 /****************************************************************************/
00022 
00023 /* RCS_INFO = "$RCSfile: dbl_mps.c,v $ $Revision: 1.2 $ $Date: 2003/11/05 16:49:52 $"; */
00024 
00025 /****************************************************************************/
00026 /*                                                                          */
00027 /*               Routines for Reading and Writing MPS Files                 */
00028 /*                                                                          */
00029 /*  EXPORTED FUNCTIONS                                                      */
00030 /*                                                                          */
00031 /*    int  ILLlpdata_mpsread (dbl_ILLlpdata *lp, const char *filename);         */
00032 /*    int  ILLlpdata_mpswrite(dbl_ILLlpdata *lp, const char *filename);         */
00033 /*                                                                          */
00034 /*  NOTES                                                                   */
00035 /*                                                                          */
00036 /*    In the MPS reader, integer variables without an explicit bound are    */
00037 /*    set to binary; real variables without an explict lower bound and      */
00038 /*    either a nonnegative or free upperbound set to nonnegative.  (These   */
00039 /*    are standard settings.)                                               */
00040 /*                                                                          */
00041 /*    If a RHS is not specified for a row, it is set to 0.                  */
00042 /*                                                                          */
00043 /*    The MPS reader allows CPLEX's OBJSENSE extension to specify max or    */
00044 /*    min and the OBJNAME extension to specify an objective row.            */
00045 /*                                                                          */
00046 /****************************************************************************/
00047 
00048 #include "econfig.h"
00049 #include "dbl_iqsutil.h"
00050 #include "dbl_mps.h"
00051 #include "dbl_rawlp.h"
00052 #include "dbl_lpdata.h"
00053 //extern double dbl_SZERO_TOLER;
00054 
00055 static int TRACE = 0;
00056 
00057 const char *dbl_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 *dbl_mps_bound_name[] = {
00064   "LO", "UP", "FX", "FR", "MI", "PL", "BV", "UI", "LI", NULL
00065 };
00066 
00067 /****************************************************************************/
00068 /* reading 
00069  */
00070 static int dbl_read_mps_section (
00071   dbl_ILLread_mps_state * state,
00072   dbl_rawlpdata * lp);
00073 
00074 static int dbl_read_mps_name (
00075   dbl_ILLread_mps_state * state,
00076   dbl_rawlpdata * lp);
00077 static int dbl_read_mps_refrow (
00078   dbl_ILLread_mps_state * state,
00079   dbl_rawlpdata * lp);
00080 static int dbl_read_mps_objnamesense (
00081   ILLmps_section sec,
00082   dbl_ILLread_mps_state * state,
00083   dbl_rawlpdata * lp);
00084 static int dbl_read_mps_objname (
00085   dbl_ILLread_mps_state * state);
00086 static int dbl_read_mps_objsense (
00087   dbl_ILLread_mps_state * state,
00088   dbl_rawlpdata * lp);
00089 
00090 static int dbl_read_mps_line_in_section (
00091   dbl_ILLread_mps_state * state,
00092   dbl_rawlpdata * lp);
00093 
00094 
00095 static int dbl_add_row (
00096   dbl_ILLread_mps_state * state,
00097   dbl_rawlpdata * lp);
00098 static int dbl_add_col (
00099   dbl_ILLread_mps_state * state,
00100   dbl_rawlpdata * lp);
00101 static int dbl_add_rhs (
00102   dbl_ILLread_mps_state * state,
00103   dbl_rawlpdata * lp);
00104 static int dbl_add_ranges (
00105   dbl_ILLread_mps_state * state,
00106   dbl_rawlpdata * lp);
00107 static int dbl_add_bounds (
00108   dbl_ILLread_mps_state * state,
00109   dbl_rawlpdata * lp);
00110 
00111 static int dbl_mps_read_marker_line (
00112   dbl_ILLread_mps_state * state,
00113   dbl_rawlpdata * lp);
00114 static int dbl_is_marker_line (
00115   dbl_ILLread_mps_state * state);
00116 static int dbl_mps_read_col_line (
00117   dbl_ILLread_mps_state * state,
00118   dbl_rawlpdata * lp);
00119 
00120 static int dbl_mps_fill_in (
00121   dbl_rawlpdata * lp,
00122   const char *obj);
00123 
00124 
00125 static void dbl_mps_set_bound (
00126   dbl_rawlpdata * lp,
00127   dbl_ILLread_mps_state * state,
00128   int colind,
00129   const char *bndtype,
00130   double bnd);
00131 
00132 int dbl_ILLread_mps (
00133   dbl_qsline_reader * file,
00134   const char *f,
00135   dbl_rawlpdata * lp)
00136 {
00137   int rval = 0;
00138   int end = 0;
00139   dbl_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 = dbl_ILLmps_state_init (&state, file, f);
00150   }
00151   if (rval != 0)
00152   {
00153     goto CLEANUP;
00154   }
00155 
00156   while (dbl_ILLmps_next_line (&state) == 0)
00157   {
00158     if (dbl_ILLmps_empty_key (&state))
00159     {
00160       if (dbl_read_mps_line_in_section (&state, lp) != 0)
00161       {
00162         rval++;
00163       }
00164     }
00165     else
00166     {
00167       /* found a section indicator in col 1 */
00168       if (!strcmp (state.key, dbl_ILLmps_section_name[ILL_MPS_ENDATA]))
00169       {
00170         end = 1;
00171         break;                  /* done reading */
00172       }
00173       if (dbl_read_mps_section (&state, lp) != 0)
00174       {
00175         rval++;
00176       }
00177     }
00178     if (rval == 50)
00179     {
00180       (void) dbl_ILLmps_error (&state, "Too many errors.\n");
00181     }
00182   }
00183 
00184   if (!end)
00185   {
00186     dbl_ILLmps_warn (&state, "Missing ENDATA.");
00187   }
00188   if (!dbl_ILLmps_next_line (&state))
00189   {
00190     dbl_ILLmps_warn (&state, "Ignoring text after ENDATA.");
00191   }
00192   if (rval == 0)
00193   {
00194     rval = dbl_mps_fill_in (lp, state.obj);
00195   }
00196 
00197 CLEANUP:
00198   ILL_RESULT (rval, "read_mps");
00199 }
00200 
00201 static int dbl_check_section_order (
00202   dbl_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 dbl_ILLmps_error (state, "%s section after ROWS section.\n",
00211                            dbl_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 dbl_ILLmps_error (state, "%s section before ROWS section.\n",
00221                            dbl_ILLmps_section_name[sec]);
00222     };
00223     break;
00224 
00225   case ILL_MPS_BOUNDS:
00226     if (state->section[ILL_MPS_COLS] == 0)
00227     {
00228       return dbl_ILLmps_error (state, "%s section before COLUMNS section.\n",
00229                            dbl_ILLmps_section_name[sec]);
00230     }
00231     break;
00232   }
00233   return 0;
00234 }
00235 
00236 static int dbl_read_mps_section (
00237   dbl_ILLread_mps_state * state,
00238   dbl_rawlpdata * lp)
00239 {
00240   int sec;
00241   int rval = 0, r;
00242 
00243   ILL_FAILtrue (dbl_ILLmps_empty_key (state), "must have a key on this line");
00244 
00245   sec = dbl_ILLutil_index (dbl_ILLmps_section_name, state->key);
00246   if (sec < 0)
00247   {
00248     return dbl_ILLmps_error (state, "\"%s\" is not a key.\n", state->key);
00249   }
00250   rval = dbl_ILLmps_set_section (state, sec);
00251 
00252   state->active = ILL_MPS_NONE;
00253   rval = rval || dbl_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 = dbl_read_mps_name (state, lp);
00265     }
00266     break;
00267 
00268   case ILL_MPS_RHS:
00269     if (rval == 0)
00270     {
00271       rval = dbl_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 = dbl_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 = dbl_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 = dbl_read_mps_objnamesense (sec, state, lp);
00295     rval = r || rval;
00296     break;
00297 
00298   case ILL_MPS_REFROW:
00299     r = dbl_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, "dbl_read_mps_section");
00309 }
00310 
00311 static int dbl_read_mps_name (
00312   dbl_ILLread_mps_state * state,
00313   dbl_rawlpdata * lp)
00314 {
00315   int rval = 0;
00316 
00317   if (dbl_ILLmps_empty_field (state))
00318   {
00319     dbl_ILLmps_warn (state, "Blank NAME.");
00320   }
00321   else
00322   {
00323     dbl_ILL_UTIL_STR (lp->name, state->field);
00324   }
00325 CLEANUP:
00326   ILL_RESULT (rval, "dbl_read_mps_name");
00327 }
00328 
00329 static int dbl_read_mps_refrow (
00330   dbl_ILLread_mps_state * state,
00331   dbl_rawlpdata * lp)
00332 {
00333   int rval = 0;
00334 
00335   rval = dbl_ILLmps_next_line (state);
00336   if (state->section[ILL_MPS_REFROW] > 1)
00337   {
00338     /* this is the second time we see this section; 
00339      * don't complain about errors */
00340     return 0;
00341   }
00342   if (dbl_ILLmps_empty_key (state) && !dbl_ILLmps_empty_field (state))
00343   {
00344     dbl_ILL_UTIL_STR (lp->refrow, state->field);
00345     return 0;
00346   }
00347   else
00348   {
00349     return dbl_ILLmps_error (state, "Bad row name in REFROW section.\n");
00350   }
00351 CLEANUP:
00352   ILL_RETURN (rval, "dbl_read_mps_refrow");
00353 }
00354 
00355 static int dbl_read_mps_objnamesense (
00356   ILLmps_section sec,
00357   dbl_ILLread_mps_state * state,
00358   dbl_rawlpdata * lp)
00359 {
00360   if (state->section[sec] > 1)
00361   {
00362     /* this is the second time we see this section; just skip next line */
00363     (void) dbl_ILLmps_next_line (state);
00364     return 0;
00365   }
00366   if (dbl_ILLmps_next_line (state) != 0)
00367   {
00368     return dbl_ILLmps_error (state, "Missing %s line at end of file.\n",
00369                          dbl_ILLmps_section_name[sec]);
00370   }
00371   if ((!dbl_ILLmps_empty_key (state)) || dbl_ILLmps_empty_field (state))
00372   {
00373     (void) dbl_ILLmps_error (state, "Bad %s in %s record.\n",
00374                          ((sec == ILL_MPS_OBJNAME) ? "row name"
00375                           : "objective sense"), dbl_ILLmps_section_name[sec]);
00376     if (!dbl_ILLmps_empty_key (state))
00377     {
00378       (void) dbl_read_mps_section (state, lp);
00379     }
00380     return 1;
00381   }
00382   if (sec == ILL_MPS_OBJNAME)
00383   {
00384     if (dbl_read_mps_objname (state))
00385     {
00386       return 1;
00387     }
00388   }
00389   else
00390   {
00391     if (dbl_read_mps_objsense (state, lp) != 0)
00392     {
00393       return 1;
00394     }
00395   }
00396   return 0;
00397 }
00398 
00399 static int dbl_read_mps_objsense (
00400   dbl_ILLread_mps_state * state,
00401   dbl_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 = dbl_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 = dbl_ILL_MIN;
00422   }
00423   else
00424   {
00425     return dbl_ILLmps_error (state, "\"%s\" is no OBJSENSE.\n", objsense);
00426   }
00427 CLEANUP:
00428   ILL_RESULT (rval, "dbl_read_mps_objsense");
00429 }
00430 
00431 static int dbl_read_mps_objname (
00432   dbl_ILLread_mps_state * state)
00433 {
00434   int rval = 0;
00435 
00436   ILL_FAILfalse (state->section[ILL_MPS_OBJNAME] == 1, "should never happen");
00437   dbl_ILL_UTIL_STR (state->obj, state->field);
00438 CLEANUP:
00439   ILL_RETURN (rval, "dbl_read_mps_objname");
00440 }
00441 
00442 static int dbl_read_mps_line_in_section (
00443   dbl_ILLread_mps_state * state,
00444   dbl_rawlpdata * lp)
00445 {
00446   int rval = 0;
00447 
00448   ILL_FAILtrue (!dbl_ILLmps_empty_key (state) || dbl_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 dbl_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 = dbl_add_row (state, lp);
00463         break;
00464       case ILL_MPS_COLS:
00465         rval = dbl_add_col (state, lp);
00466         break;
00467       case ILL_MPS_RHS:
00468         rval = dbl_add_rhs (state, lp);
00469         break;
00470       case ILL_MPS_RANGES:
00471         rval = dbl_add_ranges (state, lp);
00472         break;
00473       case ILL_MPS_BOUNDS:
00474         rval = dbl_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         /* see whether there are extra fields on line */
00483         dbl_ILLmps_check_end_of_line (state);
00484       }
00485     }
00486   }
00487 CLEANUP:
00488   ILL_RESULT (rval, "dbl_read_mps_line_in_section");
00489 }
00490 
00491 static int dbl_add_row (
00492   dbl_ILLread_mps_state * state,
00493   dbl_rawlpdata * lp)
00494 {
00495   int ind, hit, rval = 0;
00496   char sense;
00497 
00498   ILL_FAILtrue (!dbl_ILLmps_empty_key (state) || dbl_ILLmps_empty_field (state),
00499                 "no key but at least one field on state->line");
00500 
00501   /* field should contain exactly one character */
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 dbl_ILLmps_error (state,
00508                            "Unknown rowsense '%c' in ROWS record.\n", sense);
00509     }
00510     if (dbl_ILLmps_next_field (state) == 0)
00511     {
00512       hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &ind);
00513       if (!hit)
00514       {
00515         rval = dbl_ILLmps_error (state,
00516                              "Repeated row definition for \"%s\".\n",
00517                              state->field);
00518       }
00519       else
00520       {
00521         rval = dbl_ILLraw_add_row (lp, state->field, sense, dbl_zeroLpNum); /* default rhs is 0.0 */
00522       }
00523     }
00524     else
00525     {
00526       rval = dbl_ILLmps_error (state, "Missing rowname in ROWS record.\n");
00527     }
00528   }
00529   else
00530   {
00531     rval = dbl_ILLmps_error (state, "Unknown rowsense '%s' in ROWS record.\n",
00532                          state->field);
00533   }
00534 CLEANUP:
00535   ILL_RESULT (rval, "dbl_add_row");
00536 }
00537 
00538 static int dbl_add_col (
00539   dbl_ILLread_mps_state * state,
00540   dbl_rawlpdata * lp)
00541 {
00542   int rval = 0;
00543 
00544   ILL_FAILtrue (!dbl_ILLmps_empty_key (state) || dbl_ILLmps_empty_field (state),
00545                 "no key but at least one field on state->line");
00546 
00547   if (dbl_is_marker_line (state))
00548   {
00549     return dbl_mps_read_marker_line (state, lp);
00550   }
00551   else
00552   {
00553     return dbl_mps_read_col_line (state, lp);
00554   }
00555 CLEANUP:
00556   ILL_RETURN (rval, "dbl_add_col");
00557 }
00558 
00559 static int dbl_mps_read_col_line (
00560   dbl_ILLread_mps_state * state,
00561   dbl_rawlpdata * lp)
00562 {
00563   int hit, colind, rowind, rval = 0, more, ind;
00564   double ncoef;
00565 
00566   dbl_EGlpNumInitVar (ncoef);
00567 
00568   ILL_FAILtrue (!dbl_ILLmps_empty_key (state) || dbl_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 = dbl_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       /*previously declared variable is in integer section */
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 (dbl_ILLraw_is_mem_other_sos (lp, colind))
00593     {
00594       rval = dbl_ILLmps_error (state,
00595                            "\"%s\" is a member of SOS set #%d.\n",
00596                            dbl_ILLraw_colname (lp, colind),
00597                            lp->is_sos_member[colind] + 1);
00598     }
00599     else
00600     {
00601       rval = dbl_ILLraw_add_sos_member (lp, colind);
00602     }
00603     ILL_CLEANUP_IF (rval);
00604   }
00605 
00606   more = (dbl_ILLmps_next_field (state) == 0);
00607   if (!more)
00608   {
00609     return dbl_ILLmps_error (state, "Missing fields in COLUMNS record.\n");
00610   }
00611   for (more = 1; more; more = (dbl_ILLmps_next_field (state) == 0))
00612   {
00613     hit = ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind);
00614     if (hit)
00615     {
00616       return dbl_ILLmps_error (state, "\"%s\" is not a row name.\n", state->field);
00617     }
00618     if (dbl_ILLmps_next_coef (state, &ncoef) != 0)
00619     {
00620       return dbl_ILLmps_error (state,
00621                            "Missing/Bad coefficient in COLUMNS record.\n");
00622     }
00623     rval = dbl_ILLraw_add_col_coef (lp, colind, rowind, ncoef);
00624   }
00625 CLEANUP:
00626   dbl_EGlpNumClearVar (ncoef);
00627   ILL_RESULT (rval, "dbl_mps_read_col_line");
00628 }
00629 
00630 static int dbl_is_marker_line (
00631   dbl_ILLread_mps_state * state)
00632 {
00633   const char *field = state->line;
00634 
00635   while ((field = dbl_ILLutil_strchr (field, '\'')))
00636   {
00637     if (strncmp (field, "'MARKER'", (size_t) 8) == 0)
00638     {
00639       return 1;
00640     }
00641     while ((!dbl_ILL_ISBLANK (field)) && (*field != '\0'))
00642     {
00643       field++;
00644     }
00645   }
00646   return 0;
00647 }
00648 
00649 static int dbl_mps_read_marker_line (
00650   dbl_ILLread_mps_state * state,
00651   dbl_rawlpdata * lp)
00652 {
00653   int rval = 0;
00654   int sos_type = dbl_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 = dbl_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 = dbl_ILLmps_next_field (state);
00670   }
00671   rval = rval || dbl_ILLmps_next_field (state); /* swallow marker-id */
00672   if (strcmp (state->field, "'MARKER'"))
00673   {
00674     return dbl_ILLmps_error (state, "Bad 'MARKER' line.\n");
00675   }
00676   if (dbl_ILLmps_next_field (state))
00677   {
00678     return dbl_ILLmps_error (state, "Missing field on 'MARKER' line.\n");
00679   }
00680   rval = dbl_ILLmps_int_sos_mode (state);
00681   if (rval == 0)
00682   {
00683     if (cur_sos_mode != state->sosvar)
00684     {
00685       if (state->sosvar)
00686       {
00687         /* beginning of a new set */
00688         rval = dbl_ILLraw_add_sos (lp, sos_type);
00689       }
00690     }
00691   }
00692   ILL_RESULT (rval, "dbl_mps_read_marker_line");
00693 }
00694 
00695 static int dbl_add_rhs (
00696   dbl_ILLread_mps_state * state,
00697   dbl_rawlpdata * lp)
00698 {
00699   int rowind, more_fields, skip;
00700   const char *rhsname;
00701   double rhs;
00702 
00703   dbl_EGlpNumInitVar (rhs);
00704 
00705   rhsname = dbl_ILLmps_possibly_blank_name (state->field, state, &lp->rowtab);
00706   if (dbl_ILLraw_set_rhs_name (lp, rhsname, &skip))
00707   {
00708     dbl_ILLmps_error (state, "Could not add right hand side.\n");
00709   }
00710 
00711   if (skip)
00712   {
00713     dbl_ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */
00714   }
00715   else
00716   {
00717     if (strcmp (rhsname, " "))
00718     {
00719       /* field is non blank rhs name; advance to row name  */
00720       if (dbl_ILLmps_next_field (state))
00721       {
00722         return dbl_ILLmps_error (state, "Missing row name in RHS record.\n");
00723       }
00724     }
00725     for (more_fields = 1; more_fields; more_fields = !dbl_ILLmps_next_field (state))
00726     {
00727       if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind))
00728       {
00729         return dbl_ILLmps_error (state, "\"%s\" is not a row name.\n",
00730                              state->field);
00731       }
00732       if (dbl_ILLmps_next_coef (state, &rhs))
00733       {
00734         return dbl_ILLmps_error (state, "Missing/Bad coefficient in RHS record.\n");
00735       }
00736       if (lp->rhsind[rowind])
00737       {
00738         return dbl_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           dbl_ILLmps_warn (state,
00746                        "Ignoring right hand side for N-row \"%s\".",
00747                        dbl_ILLraw_rowname (lp, rowind));
00748         }
00749         else
00750         {
00751           dbl_EGlpNumCopy (lp->rhs[rowind], rhs);
00752           lp->rhsind[rowind] = 1;
00753         }
00754       }
00755     }
00756   }
00757   dbl_EGlpNumClearVar (rhs);
00758   return 0;
00759 }
00760 
00761 static int dbl_add_bounds (
00762   dbl_ILLread_mps_state * state,
00763   dbl_rawlpdata * lp)
00764 {
00765   char bndtype[3];
00766   const char *bounds_name;
00767   int colind, skip, rval = 0;
00768   double bnd;
00769 
00770   dbl_EGlpNumInitVar (bnd);
00771 
00772   ILL_FAILtrue (!dbl_ILLmps_empty_key (state) || dbl_ILLmps_empty_field (state),
00773                 "no key but at least one field on state->line");
00774 
00775   if (dbl_ILLutil_index (dbl_mps_bound_name, state->field) < 0)
00776   {
00777     return dbl_ILLmps_error (state, "\"%s\" is not a BOUNDS type.\n", state->field);
00778   }
00779   strcpy (bndtype, state->field);
00780 
00781   if (dbl_ILLmps_next_field (state) != 0)
00782   {
00783     return dbl_ILLmps_error (state,
00784                          "No bounds/column identifier in BOUNDS record.\n");
00785   }
00786 
00787   bounds_name = dbl_ILLmps_possibly_blank_name (state->field, state, &lp->coltab);
00788   if (bounds_name == NULL)
00789   {
00790     return 1;
00791   }
00792   if (dbl_ILLraw_set_bounds_name (lp, bounds_name, &skip))
00793   {
00794     return 1;
00795   }
00796   if (skip)
00797   {
00798     dbl_ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */
00799   }
00800   else
00801   {
00802     if (strcmp (bounds_name, " "))
00803     {
00804       /* non empty bounds_name ==> advance to col name field */
00805       if (dbl_ILLmps_next_field (state))
00806       {
00807         return dbl_ILLmps_error (state, "Missing column field in BOUNDS record.\n");
00808       }
00809     }
00810     if (ILLsymboltab_lookup (&lp->coltab, state->field, &colind))
00811     {
00812       return dbl_ILLmps_error (state, "\"%s\" is not a column name.\n",
00813                            state->field);
00814     }
00815     dbl_EGlpNumZero (bnd);
00816     if (strcmp (bndtype, "FR") && strcmp (bndtype, "BV") &&
00817         strcmp (bndtype, "MI") && strcmp (bndtype, "PL"))
00818     {
00819       /* neither "FR", "BV", "MI" nor "PL" ==> there should be a bound */
00820       if (dbl_ILLmps_next_bound (state, &bnd))
00821       {
00822         return dbl_ILLmps_error (state,
00823                              "Missing/Bad bound field in BOUNDS record.\n");
00824       }
00825     }
00826     dbl_mps_set_bound (lp, state, colind, bndtype, bnd);
00827   }
00828 CLEANUP:
00829   dbl_EGlpNumClearVar (bnd);
00830   ILL_RESULT (rval, "dbl_add_bounds");
00831 }
00832 
00833 static void dbl_mps_set_bound (
00834   dbl_rawlpdata * lp,
00835   dbl_ILLread_mps_state * state,
00836   int colind,
00837   const char *bndtype,
00838   double bnd)
00839 {
00840   const char *msg = NULL;
00841 
00842   if (!strcmp (bndtype, "LO"))
00843   {
00844     msg = dbl_ILLraw_set_lowerBound (lp, colind, bnd);
00845   }
00846   else if (!strcmp (bndtype, "UP"))
00847   {
00848     msg = dbl_ILLraw_set_upperBound (lp, colind, bnd);
00849   }
00850   else if (!strcmp (bndtype, "FX"))
00851   {
00852     msg = dbl_ILLraw_set_fixedBound (lp, colind, bnd);
00853   }
00854   else if (!strcmp (bndtype, "FR"))
00855   {
00856     msg = dbl_ILLraw_set_unbound (lp, colind);
00857   }
00858   else if (!strcmp (bndtype, "BV"))
00859   {
00860     msg = dbl_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 = dbl_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 = dbl_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 = dbl_ILLraw_set_lowerBound (lp, colind, dbl_ILL_MINDOUBLE);
00885   }
00886   else if (!strcmp (bndtype, "PL"))
00887   {
00888     msg = dbl_ILLraw_set_upperBound (lp, colind, dbl_ILL_MAXDOUBLE);
00889   }
00890   else
00891   {
00892     ILL_REPRT ("should never get here");
00893     ILL_CLEANUP;
00894   }
00895   dbl_ILLmps_warn (state, msg);
00896 CLEANUP:
00897   return;
00898 }
00899 
00900 static int dbl_add_ranges (
00901   dbl_ILLread_mps_state * state,
00902   dbl_rawlpdata * lp)
00903 {
00904   const char *rangesname;
00905   int skip, more_fields, rowind;
00906   double ntmp;
00907 
00908   dbl_EGlpNumInitVar (ntmp);
00909 
00910   rangesname = dbl_ILLmps_possibly_blank_name (state->field, state, &lp->rowtab);
00911   if (dbl_ILLraw_set_ranges_name (lp, rangesname, &skip))
00912   {
00913     return dbl_ILLmps_error (state, "Could not add range.\n");
00914   }
00915   if (skip)
00916   {
00917     dbl_ILLmps_set_end_of_line (state); /* to avoid warning about extra fields */
00918   }
00919   else
00920   {
00921     if (strcmp (rangesname, " "))
00922     {
00923       /* field is non blank ranges name; advance to row name */
00924       if (dbl_ILLmps_next_field (state))
00925       {
00926         return dbl_ILLmps_error (state, "Missing row name in RANGES record.");
00927       }
00928     }
00929     for (more_fields = 1; more_fields; more_fields = !dbl_ILLmps_next_field (state))
00930     {
00931       if (ILLsymboltab_lookup (&lp->rowtab, state->field, &rowind))
00932       {
00933         return dbl_ILLmps_error (state, "\"%s\" is not a row name.\n",
00934                              state->field);
00935       }
00936       if (dbl_ILLmps_next_coef (state, &ntmp))
00937       {
00938         return dbl_ILLmps_error (state,
00939                              "Missing/Bad coefficient in RANGES record.\n");
00940       }
00941       if (lp->rangesind[rowind])
00942       {
00943         dbl_ILLmps_warn (state, "Ignoring second RANGE value %s \"%s\".",
00944                      "for row", dbl_ILLraw_rowname (lp, rowind));
00945       }
00946       else
00947       {
00948         if (lp->rowsense[rowind] != 'N')
00949         {
00950           if (dbl_ILLraw_add_ranges_coef (lp, rowind, ntmp))
00951             return 1;
00952         }
00953         else
00954         {
00955           dbl_ILLmps_warn (state, "Ignoring RANGE value for N-row \"%s\".",
00956                        dbl_ILLraw_rowname (lp, rowind));
00957         }
00958       }
00959     }
00960   }
00961   dbl_EGlpNumClearVar (ntmp);
00962   return 0;
00963 }
00964 
00965 
00966 static int dbl_mps_fill_in (
00967   dbl_rawlpdata * lp,
00968   const char *obj)
00969 {
00970   int i, hit, rval = 0;
00971 
00972   /* find the objective function -- the first N row if obj is not defined  */
00973   if (obj)
00974   {
00975     hit = ILLsymboltab_lookup (&lp->rowtab, obj, &lp->objindex);
00976     if (hit)
00977     {
00978       return dbl_ILLdata_error (lp->error_collector,
00979                             "Bad objective name \"%s\".\n", obj);
00980     }
00981     else if (lp->rowsense[lp->objindex] != 'N')
00982     {
00983       dbl_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 dbl_ILLdata_error (lp->error_collector,
01001                             "No N-row in lp definition.\n");
01002     }
01003   }
01004 
01005   if (lp->ncols > 0)
01006   {
01007     rval = dbl_ILLraw_fill_in_bounds (lp);
01008   }
01009 
01010   /* set weights of sos set members */
01011   if (lp->refrow)
01012   {
01013     /* take the values from refrow */
01014     double weight;
01015     dbl_colptr *cp;
01016 
01017     dbl_EGlpNumInitVar (weight);
01018 
01019     hit = ILLsymboltab_lookup (&lp->rowtab, lp->refrow, &lp->refrowind);
01020     if (hit)
01021     {
01022       return dbl_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) && dbl_EGlpNumIsNeqqZero (cp->coef))
01033       {
01034         dbl_EGlpNumCopy (weight, cp->coef);
01035       }
01036       else
01037       {
01038         dbl_ILLdata_warn (lp->error_collector,
01039                       "\"%s\" has 0.0 coefficient in REFROW \"%s\".",
01040                       dbl_ILLraw_colname (lp, lp->sos_col[i]), lp->refrow);
01041         dbl_EGlpNumZero (weight);
01042       }
01043       dbl_EGlpNumCopy (lp->sos_weight[i], weight);
01044     }
01045     dbl_EGlpNumClearVar (weight);
01046   }
01047   else
01048   {                             /* no refrow */
01049     /* set weights to 1, 2, 3, ... in order of definition */
01050     int si, w;
01051     dbl_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         dbl_EGlpNumSet (lp->sos_weight[i], (double) w);
01060         w++;
01061       }
01062     }
01063   }
01064   ILL_IFTRACE ("bound %lf <= x1 <= %lf\n", dbl_EGlpNumToLf (lp->lower[0]),
01065                dbl_EGlpNumToLf (lp->upper[0]));
01066   ILL_IFTRACE ("MAXDOUBLE %lf MINDOUBLE %lf\n", dbl_EGlpNumToLf (dbl_ILL_MAXDOUBLE),
01067                dbl_EGlpNumToLf (dbl_ILL_MINDOUBLE));
01068   ILL_RESULT (rval, "dbl_mps_fill_in");
01069 }
01070 
01071 /****************************************************************************/
01072 /* writing 
01073  */
01074 
01075 static int dbl_mps_write_col (
01076   int i,
01077   int iorig,
01078   char *colname,
01079   dbl_ILLlpdata * lp,
01080   char **rownames,
01081   int intmode,
01082   char *objname);
01083 
01084 int dbl_ILLwrite_mps (
01085   dbl_ILLlpdata * lp,
01086   dbl_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   dbl_ILLlp_rows lp_rows, *lprows = NULL;
01095   char buf[ILL_namebufsize];
01096   char *objname = NULL;
01097 
01098   ILL_CHECKnull (lp, "lp must not be null");
01099   ILL_FAILtrue (lp->probname == NULL, "oops should never happen");
01100 
01101   ILL_FAILfalse (lp->colnames != NULL, "colnames != NULL");
01102   ILL_FAILfalse (lp->rownames != NULL, "colnames != NULL");
01103   colnames = lp->colnames;
01104   rownames = lp->rownames;
01105 
01106   objname = lp->objname;
01107   if (objname == (char *) NULL)
01108   {
01109     strcpy (buf, "obj");
01110     rval = ILLsymboltab_uname (&lp->rowtab, buf, "", NULL);
01111     ILL_CLEANUP_IF (rval);
01112     dbl_ILL_UTIL_STR (objname, buf);
01113   }
01114   dbl_ILLprint_report (lp, "NAME    %s\n", lp->probname);
01115   dbl_ILLprint_report (lp, "OBJSENSE\n  %s\n",
01116                    (lp->objsense == dbl_ILL_MIN) ? "MIN" : "MAX");
01117   dbl_ILLprint_report (lp, "OBJNAME\n  %s\n", objname);
01118   if (lp->refrowname)
01119   {
01120     dbl_ILLprint_report (lp, "REFROW\n");
01121     dbl_ILLprint_report (lp, " %s\n", lp->refrowname);
01122   }
01123 
01124 
01125   dbl_ILLprint_report (lp, "ROWS\n");
01126   dbl_ILLprint_report (lp, " N  %s\n", objname);
01127   if (lp->refrowname && (lp->refind == -1))
01128   {
01129     dbl_ILLprint_report (lp, " N  %s\n", lp->refrowname);
01130   }
01131 
01132   lprows = &lp_rows;
01133   rval = dbl_ILLlp_rows_init (lprows, lp, 0);
01134   ILL_CLEANUP_IF (rval);
01135   for (i = 0; i < lp->nrows; i++)
01136   {
01137     if (lprows->rowcnt[i] == 0)
01138     {
01139       dbl_ILLdata_warn (collector,
01140                     "Deleting empty row \"%s\" from constraints.", rownames[i]);
01141       continue;
01142     }
01143     switch (lp->sense[i])
01144     {
01145     case 'G':
01146       dbl_ILLprint_report (lp, " G  ");
01147       break;
01148     case 'L':
01149       dbl_ILLprint_report (lp, " L  ");
01150       break;
01151     case 'E':
01152       dbl_ILLprint_report (lp, " E  ");
01153       break;
01154     case 'R':
01155       dbl_ILLprint_report (lp, " G  ");
01156       break;
01157     }
01158     dbl_ILLprint_report (lp, "%s\n", rownames[i]);
01159   }
01160 
01161   dbl_ILLprint_report (lp, "COLUMNS\n");
01162   for (set = 0; set < lp->sos.matcols; set++)
01163   {
01164     ILL_FAILtrue (lp->sos_type == NULL, "must have non NULL sos_type");
01165     ILL_FAILtrue (lp->is_sos_mem == NULL, "must have non NULL is_sos_mem");
01166     empty = 1;
01167     for (el = lp->sos.matbeg[set];
01168          el < lp->sos.matbeg[set] + lp->sos.matcnt[set]; el++)
01169     {
01170       if (empty)
01171       {
01172         dbl_ILLprint_report (lp, " %s SOS%dqs    'MARKER'    'SOSORG'\n",
01173                          ((lp->sos_type[set] == dbl_ILL_SOS_TYPE1)) ? "S1" : "S2",
01174                          marker++);
01175         empty = 0;
01176       }
01177       ri = lp->sos.matind[el];
01178       i = lp->structmap[ri];
01179       intmode = dbl_mps_write_col (i, ri, colnames[ri], lp, rownames,
01180                                intmode, objname);
01181       if (lp->refrowname && (lp->refind == -1))
01182       {
01183         dbl_ILLprint_report (lp, "  %s    %s    %g\n",
01184                          colnames[ri], lp->refrowname, lp->sos.matval[el]);
01185       }
01186     }
01187     if (!empty)
01188     {
01189       dbl_ILLprint_report (lp, " SOS%dqs       'MARKER'    'SOSEND'\n", marker++);
01190     }
01191   }
01192   for (ri = 0; ri < lp->nstruct; ri++)
01193   {
01194     if (lp->is_sos_mem == (int *) NULL || lp->is_sos_mem[ri] == -1)
01195     {
01196       i = lp->structmap[ri];
01197       intmode = dbl_mps_write_col (i, ri, colnames[ri], lp, rownames,
01198                                intmode, objname);
01199     }
01200   }
01201   if (intmode)
01202   {
01203     dbl_ILLprint_report (lp, " MARK%dqs      'MARKER'    'INTEND'\n", lp->nstruct);
01204   }
01205 
01206   dbl_ILLprint_report (lp, "RHS\n");
01207   for (i = 0; i < lp->nrows; i++)
01208   {
01209     if ((lprows->rowcnt[i] != 0) && dbl_EGlpNumIsNeqqZero (lp->rhs[i]))
01210     {
01211       dbl_ILLprint_report (lp, " RHS    %s    %g\n", rownames[i],
01212                        dbl_EGlpNumToLf (lp->rhs[i]));
01213     }
01214   }
01215 
01216   if (lp->rangeval)
01217   {
01218     dbl_ILLprint_report (lp, "RANGES\n");
01219     for (i = 0; i < lp->nrows; i++)
01220     {
01221       if ((lprows->rowcnt[i] != 0) && dbl_EGlpNumIsNeqqZero (lp->rangeval[i]))
01222       {
01223         dbl_ILLprint_report (lp, " RANGE    %s    %g\n", rownames[i],
01224                          dbl_EGlpNumToLf (lp->rangeval[i]));
01225       }
01226     }
01227   }
01228 
01229   ri = dbl_ILLraw_first_nondefault_bound (lp);
01230   if (ri != lp->nstruct)
01231   {
01232     dbl_ILLprint_report (lp, "BOUNDS\n");
01233     for (ri = ri; ri < lp->nstruct; ri++)
01234     {
01235       i = lp->structmap[ri];
01236       if (dbl_EGlpNumIsEqqual (lp->lower[i], lp->upper[i]))
01237       {
01238         dbl_ILLprint_report (lp, " FX BOUND    %s    %g\n", colnames[ri],
01239                          dbl_EGlpNumToLf (lp->lower[i]));
01240         continue;
01241       }
01242       if ((dbl_EGlpNumIsEqqual (lp->lower[i], dbl_ILL_MINDOUBLE)) &&
01243           (dbl_EGlpNumIsEqqual (lp->upper[i], dbl_ILL_MAXDOUBLE)))
01244       {
01245         dbl_ILLprint_report (lp, " FR BOUND    %s\n", colnames[ri]);
01246         continue;
01247       }
01248       prtLower = !dbl_ILLraw_default_lower (lp, i);
01249       prtUpper = !dbl_ILLraw_default_upper (lp, i);
01250       if (prtLower)
01251       {
01252         if (dbl_EGlpNumIsEqqual (lp->lower[i], dbl_ILL_MINDOUBLE))
01253         {
01254           dbl_ILLprint_report (lp, " MI BOUND    %s\n", colnames[ri]);
01255         }
01256         else
01257         {
01258           dbl_ILLprint_report (lp, " LO BOUND    %s    %g\n", colnames[ri],
01259                            dbl_EGlpNumToLf (lp->lower[i]));
01260         }
01261       }
01262       if (prtUpper)
01263       {
01264         if (dbl_EGlpNumIsEqqual (lp->upper[i], dbl_ILL_MAXDOUBLE))
01265         {
01266           dbl_ILLprint_report (lp, " PL BOUND    %s\n", colnames[ri]);
01267         }
01268         else
01269         {
01270           dbl_ILLprint_report (lp, " UP BOUND    %s    %g\n", colnames[ri],
01271                            dbl_EGlpNumToLf (lp->upper[i]));
01272         }
01273       }
01274     }
01275   }
01276   dbl_ILLprint_report (lp, "ENDATA\n");
01277 
01278 CLEANUP:
01279   dbl_ILLlp_rows_clear (lprows);
01280   if (!lp->colnames)
01281   {
01282     ILLfree_names (colnames, lp->ncols);
01283   }
01284   if (!lp->rownames)
01285   {
01286     ILLfree_names (rownames, lp->nrows);
01287   }
01288   if (objname != lp->objname)
01289   {
01290     ILL_IFFREE (objname, char);
01291   }
01292   ILL_RESULT (rval, "ILLlpdata_mpswrite");
01293 }
01294 
01295 static int dbl_mps_write_col (
01296   int i,
01297   int iorig,
01298   char *colname,
01299   dbl_ILLlpdata * lp,
01300   char **rownames,
01301   int intmode,
01302   char *objname)
01303 {
01304   int row, k;
01305   dbl_ILLmatrix *A;
01306 
01307   A = &lp->A;
01308   if (lp->intmarker && (lp->intmarker[iorig] != intmode))
01309   {
01310     dbl_ILLprint_report (lp, " MARK%dqs      'MARKER'    '%s'\n", iorig,
01311                      (lp->intmarker[iorig] ? "INTORG" : "INTEND"));
01312     intmode = lp->intmarker[iorig];
01313   }
01314   if (dbl_EGlpNumIsNeqqZero (lp->obj[i]))
01315   {
01316     dbl_ILLprint_report (lp, "  %s    %s    %g\n", colname, objname,
01317                      dbl_EGlpNumToLf (lp->obj[i]));
01318   }
01319   for (k = A->matbeg[i]; k < A->matbeg[i] + A->matcnt[i]; k++)
01320   {
01321     row = A->matind[k];
01322     dbl_ILLprint_report (lp, "  %s    %s    %g\n", colname, rownames[row],
01323                      dbl_EGlpNumToLf (A->matval[k]));
01324   }
01325   return intmode;
01326 }

Generated on Wed Apr 22 09:16:09 2009 for QSopt_ex by  doxygen 1.5.2