src/glpcpx.c
changeset 1 c445c931472f
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/glpcpx.c	Mon Dec 06 13:09:21 2010 +0100
     1.3 @@ -0,0 +1,1239 @@
     1.4 +/* glpcpx.c (CPLEX LP format routines) */
     1.5 +
     1.6 +/***********************************************************************
     1.7 +*  This code is part of GLPK (GNU Linear Programming Kit).
     1.8 +*
     1.9 +*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
    1.10 +*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
    1.11 +*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
    1.12 +*  E-mail: <mao@gnu.org>.
    1.13 +*
    1.14 +*  GLPK is free software: you can redistribute it and/or modify it
    1.15 +*  under the terms of the GNU General Public License as published by
    1.16 +*  the Free Software Foundation, either version 3 of the License, or
    1.17 +*  (at your option) any later version.
    1.18 +*
    1.19 +*  GLPK is distributed in the hope that it will be useful, but WITHOUT
    1.20 +*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
    1.21 +*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
    1.22 +*  License for more details.
    1.23 +*
    1.24 +*  You should have received a copy of the GNU General Public License
    1.25 +*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
    1.26 +***********************************************************************/
    1.27 +
    1.28 +#include "glpapi.h"
    1.29 +
    1.30 +/***********************************************************************
    1.31 +*  NAME
    1.32 +*
    1.33 +*  glp_init_cpxcp - initialize CPLEX LP format control parameters
    1.34 +*
    1.35 +*  SYNOPSIS
    1.36 +*
    1.37 +*  void glp_init_cpxcp(glp_cpxcp *parm):
    1.38 +*
    1.39 +*  The routine glp_init_cpxcp initializes control parameters used by
    1.40 +*  the CPLEX LP input/output routines glp_read_lp and glp_write_lp with
    1.41 +*  default values.
    1.42 +*
    1.43 +*  Default values of the control parameters are stored in the glp_cpxcp
    1.44 +*  structure, which the parameter parm points to. */
    1.45 +
    1.46 +void glp_init_cpxcp(glp_cpxcp *parm)
    1.47 +{     xassert(parm != NULL);
    1.48 +      return;
    1.49 +}
    1.50 +
    1.51 +static void check_parm(const char *func, const glp_cpxcp *parm)
    1.52 +{     /* check control parameters */
    1.53 +      xassert(func != NULL);
    1.54 +      xassert(parm != NULL);
    1.55 +      return;
    1.56 +}
    1.57 +
    1.58 +/***********************************************************************
    1.59 +*  NAME
    1.60 +*
    1.61 +*  glp_read_lp - read problem data in CPLEX LP format
    1.62 +*
    1.63 +*  SYNOPSIS
    1.64 +*
    1.65 +*  int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char
    1.66 +*     *fname);
    1.67 +*
    1.68 +*  DESCRIPTION
    1.69 +*
    1.70 +*  The routine glp_read_lp reads problem data in CPLEX LP format from
    1.71 +*  a text file.
    1.72 +*
    1.73 +*  The parameter parm is a pointer to the structure glp_cpxcp, which
    1.74 +*  specifies control parameters used by the routine. If parm is NULL,
    1.75 +*  the routine uses default settings.
    1.76 +*
    1.77 +*  The character string fname specifies a name of the text file to be
    1.78 +*  read.
    1.79 +*
    1.80 +*  Note that before reading data the current content of the problem
    1.81 +*  object is completely erased with the routine glp_erase_prob.
    1.82 +*
    1.83 +*  RETURNS
    1.84 +*
    1.85 +*  If the operation was successful, the routine glp_read_lp returns
    1.86 +*  zero. Otherwise, it prints an error message and returns non-zero. */
    1.87 +
    1.88 +struct csa
    1.89 +{     /* common storage area */
    1.90 +      glp_prob *P;
    1.91 +      /* LP/MIP problem object */
    1.92 +      const glp_cpxcp *parm;
    1.93 +      /* pointer to control parameters */
    1.94 +      const char *fname;
    1.95 +      /* name of input CPLEX LP file */
    1.96 +      XFILE *fp;
    1.97 +      /* stream assigned to input CPLEX LP file */
    1.98 +      jmp_buf jump;
    1.99 +      /* label for go to in case of error */
   1.100 +      int count;
   1.101 +      /* line count */
   1.102 +      int c;
   1.103 +      /* current character or XEOF */
   1.104 +      int token;
   1.105 +      /* current token: */
   1.106 +#define T_EOF        0x00  /* end of file */
   1.107 +#define T_MINIMIZE   0x01  /* keyword 'minimize' */
   1.108 +#define T_MAXIMIZE   0x02  /* keyword 'maximize' */
   1.109 +#define T_SUBJECT_TO 0x03  /* keyword 'subject to' */
   1.110 +#define T_BOUNDS     0x04  /* keyword 'bounds' */
   1.111 +#define T_GENERAL    0x05  /* keyword 'general' */
   1.112 +#define T_INTEGER    0x06  /* keyword 'integer' */
   1.113 +#define T_BINARY     0x07  /* keyword 'binary' */
   1.114 +#define T_END        0x08  /* keyword 'end' */
   1.115 +#define T_NAME       0x09  /* symbolic name */
   1.116 +#define T_NUMBER     0x0A  /* numeric constant */
   1.117 +#define T_PLUS       0x0B  /* delimiter '+' */
   1.118 +#define T_MINUS      0x0C  /* delimiter '-' */
   1.119 +#define T_COLON      0x0D  /* delimiter ':' */
   1.120 +#define T_LE         0x0E  /* delimiter '<=' */
   1.121 +#define T_GE         0x0F  /* delimiter '>=' */
   1.122 +#define T_EQ         0x10  /* delimiter '=' */
   1.123 +      char image[255+1];
   1.124 +      /* image of current token */
   1.125 +      int imlen;
   1.126 +      /* length of token image */
   1.127 +      double value;
   1.128 +      /* value of numeric constant */
   1.129 +      int n_max;
   1.130 +      /* length of the following five arrays (enlarged automatically,
   1.131 +         if necessary) */
   1.132 +      int *ind; /* int ind[1+n_max]; */
   1.133 +      double *val; /* double val[1+n_max]; */
   1.134 +      char *flag; /* char flag[1+n_max]; */
   1.135 +      /* working arrays used to construct linear forms */
   1.136 +      double *lb; /* double lb[1+n_max]; */
   1.137 +      double *ub; /* double ub[1+n_max]; */
   1.138 +      /* lower and upper bounds of variables (columns) */
   1.139 +};
   1.140 +
   1.141 +#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~"
   1.142 +/* characters, which may appear in symbolic names */
   1.143 +
   1.144 +static void error(struct csa *csa, const char *fmt, ...)
   1.145 +{     /* print error message and terminate processing */
   1.146 +      va_list arg;
   1.147 +      xprintf("%s:%d: ", csa->fname, csa->count);
   1.148 +      va_start(arg, fmt);
   1.149 +      xvprintf(fmt, arg);
   1.150 +      va_end(arg);
   1.151 +      longjmp(csa->jump, 1);
   1.152 +      /* no return */
   1.153 +}
   1.154 +
   1.155 +static void warning(struct csa *csa, const char *fmt, ...)
   1.156 +{     /* print warning message and continue processing */
   1.157 +      va_list arg;
   1.158 +      xprintf("%s:%d: warning: ", csa->fname, csa->count);
   1.159 +      va_start(arg, fmt);
   1.160 +      xvprintf(fmt, arg);
   1.161 +      va_end(arg);
   1.162 +      return;
   1.163 +}
   1.164 +
   1.165 +static void read_char(struct csa *csa)
   1.166 +{     /* read next character from input file */
   1.167 +      int c;
   1.168 +      xassert(csa->c != XEOF);
   1.169 +      if (csa->c == '\n') csa->count++;
   1.170 +      c = xfgetc(csa->fp);
   1.171 +      if (c < 0)
   1.172 +      {  if (xferror(csa->fp))
   1.173 +            error(csa, "read error - %s\n", xerrmsg());
   1.174 +         else if (csa->c == '\n')
   1.175 +         {  csa->count--;
   1.176 +            c = XEOF;
   1.177 +         }
   1.178 +         else
   1.179 +         {  warning(csa, "missing final end of line\n");
   1.180 +            c = '\n';
   1.181 +         }
   1.182 +      }
   1.183 +      else if (c == '\n')
   1.184 +         ;
   1.185 +      else if (isspace(c))
   1.186 +         c = ' ';
   1.187 +      else if (iscntrl(c))
   1.188 +         error(csa, "invalid control character 0x%02X\n", c);
   1.189 +      csa->c = c;
   1.190 +      return;
   1.191 +}
   1.192 +
   1.193 +static void add_char(struct csa *csa)
   1.194 +{     /* append current character to current token */
   1.195 +      if (csa->imlen == sizeof(csa->image)-1)
   1.196 +         error(csa, "token `%.15s...' too long\n", csa->image);
   1.197 +      csa->image[csa->imlen++] = (char)csa->c;
   1.198 +      csa->image[csa->imlen] = '\0';
   1.199 +      read_char(csa);
   1.200 +      return;
   1.201 +}
   1.202 +
   1.203 +static int the_same(char *s1, char *s2)
   1.204 +{     /* compare two character strings ignoring case sensitivity */
   1.205 +      for (; *s1 != '\0'; s1++, s2++)
   1.206 +      {  if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2))
   1.207 +            return 0;
   1.208 +      }
   1.209 +      return 1;
   1.210 +}
   1.211 +
   1.212 +static void scan_token(struct csa *csa)
   1.213 +{     /* scan next token */
   1.214 +      int flag;
   1.215 +      csa->token = -1;
   1.216 +      csa->image[0] = '\0';
   1.217 +      csa->imlen = 0;
   1.218 +      csa->value = 0.0;
   1.219 +loop: flag = 0;
   1.220 +      /* skip non-significant characters */
   1.221 +      while (csa->c == ' ') read_char(csa);
   1.222 +      /* recognize and scan current token */
   1.223 +      if (csa->c == XEOF)
   1.224 +         csa->token = T_EOF;
   1.225 +      else if (csa->c == '\n')
   1.226 +      {  read_char(csa);
   1.227 +         /* if the next character is letter, it may begin a keyword */
   1.228 +         if (isalpha(csa->c))
   1.229 +         {  flag = 1;
   1.230 +            goto name;
   1.231 +         }
   1.232 +         goto loop;
   1.233 +      }
   1.234 +      else if (csa->c == '\\')
   1.235 +      {  /* comment; ignore everything until end-of-line */
   1.236 +         while (csa->c != '\n') read_char(csa);
   1.237 +         goto loop;
   1.238 +      }
   1.239 +      else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET,
   1.240 +         csa->c) != NULL)
   1.241 +name: {  /* symbolic name */
   1.242 +         csa->token = T_NAME;
   1.243 +         while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL)
   1.244 +            add_char(csa);
   1.245 +         if (flag)
   1.246 +         {  /* check for keyword */
   1.247 +            if (the_same(csa->image, "minimize"))
   1.248 +               csa->token = T_MINIMIZE;
   1.249 +            else if (the_same(csa->image, "minimum"))
   1.250 +               csa->token = T_MINIMIZE;
   1.251 +            else if (the_same(csa->image, "min"))
   1.252 +               csa->token = T_MINIMIZE;
   1.253 +            else if (the_same(csa->image, "maximize"))
   1.254 +               csa->token = T_MAXIMIZE;
   1.255 +            else if (the_same(csa->image, "maximum"))
   1.256 +               csa->token = T_MAXIMIZE;
   1.257 +            else if (the_same(csa->image, "max"))
   1.258 +               csa->token = T_MAXIMIZE;
   1.259 +            else if (the_same(csa->image, "subject"))
   1.260 +            {  if (csa->c == ' ')
   1.261 +               {  read_char(csa);
   1.262 +                  if (tolower(csa->c) == 't')
   1.263 +                  {  csa->token = T_SUBJECT_TO;
   1.264 +                     csa->image[csa->imlen++] = ' ';
   1.265 +                     csa->image[csa->imlen] = '\0';
   1.266 +                     add_char(csa);
   1.267 +                     if (tolower(csa->c) != 'o')
   1.268 +                        error(csa, "keyword `subject to' incomplete\n");
   1.269 +                     add_char(csa);
   1.270 +                     if (isalpha(csa->c))
   1.271 +                        error(csa, "keyword `%s%c...' not recognized\n",
   1.272 +                           csa->image, csa->c);
   1.273 +                  }
   1.274 +               }
   1.275 +            }
   1.276 +            else if (the_same(csa->image, "such"))
   1.277 +            {  if (csa->c == ' ')
   1.278 +               {  read_char(csa);
   1.279 +                  if (tolower(csa->c) == 't')
   1.280 +                  {  csa->token = T_SUBJECT_TO;
   1.281 +                     csa->image[csa->imlen++] = ' ';
   1.282 +                     csa->image[csa->imlen] = '\0';
   1.283 +                     add_char(csa);
   1.284 +                     if (tolower(csa->c) != 'h')
   1.285 +err:                    error(csa, "keyword `such that' incomplete\n");
   1.286 +                     add_char(csa);
   1.287 +                     if (tolower(csa->c) != 'a') goto err;
   1.288 +                     add_char(csa);
   1.289 +                     if (tolower(csa->c) != 't') goto err;
   1.290 +                     add_char(csa);
   1.291 +                     if (isalpha(csa->c))
   1.292 +                        error(csa, "keyword `%s%c...' not recognized\n",
   1.293 +                           csa->image, csa->c);
   1.294 +                  }
   1.295 +               }
   1.296 +            }
   1.297 +            else if (the_same(csa->image, "st"))
   1.298 +               csa->token = T_SUBJECT_TO;
   1.299 +            else if (the_same(csa->image, "s.t."))
   1.300 +               csa->token = T_SUBJECT_TO;
   1.301 +            else if (the_same(csa->image, "st."))
   1.302 +               csa->token = T_SUBJECT_TO;
   1.303 +            else if (the_same(csa->image, "bounds"))
   1.304 +               csa->token = T_BOUNDS;
   1.305 +            else if (the_same(csa->image, "bound"))
   1.306 +               csa->token = T_BOUNDS;
   1.307 +            else if (the_same(csa->image, "general"))
   1.308 +               csa->token = T_GENERAL;
   1.309 +            else if (the_same(csa->image, "generals"))
   1.310 +               csa->token = T_GENERAL;
   1.311 +            else if (the_same(csa->image, "gen"))
   1.312 +               csa->token = T_GENERAL;
   1.313 +            else if (the_same(csa->image, "integer"))
   1.314 +               csa->token = T_INTEGER;
   1.315 +            else if (the_same(csa->image, "integers"))
   1.316 +               csa->token = T_INTEGER;
   1.317 +            else if (the_same(csa->image, "int"))
   1.318 +              csa->token = T_INTEGER;
   1.319 +            else if (the_same(csa->image, "binary"))
   1.320 +               csa->token = T_BINARY;
   1.321 +            else if (the_same(csa->image, "binaries"))
   1.322 +               csa->token = T_BINARY;
   1.323 +            else if (the_same(csa->image, "bin"))
   1.324 +               csa->token = T_BINARY;
   1.325 +            else if (the_same(csa->image, "end"))
   1.326 +               csa->token = T_END;
   1.327 +         }
   1.328 +      }
   1.329 +      else if (isdigit(csa->c) || csa->c == '.')
   1.330 +      {  /* numeric constant */
   1.331 +         csa->token = T_NUMBER;
   1.332 +         /* scan integer part */
   1.333 +         while (isdigit(csa->c)) add_char(csa);
   1.334 +         /* scan optional fractional part (it is mandatory, if there is
   1.335 +            no integer part) */
   1.336 +         if (csa->c == '.')
   1.337 +         {  add_char(csa);
   1.338 +            if (csa->imlen == 1 && !isdigit(csa->c))
   1.339 +               error(csa, "invalid use of decimal point\n");
   1.340 +            while (isdigit(csa->c)) add_char(csa);
   1.341 +         }
   1.342 +         /* scan optional decimal exponent */
   1.343 +         if (csa->c == 'e' || csa->c == 'E')
   1.344 +         {  add_char(csa);
   1.345 +            if (csa->c == '+' || csa->c == '-') add_char(csa);
   1.346 +            if (!isdigit(csa->c))
   1.347 +               error(csa, "numeric constant `%s' incomplete\n",
   1.348 +                  csa->image);
   1.349 +            while (isdigit(csa->c)) add_char(csa);
   1.350 +         }
   1.351 +         /* convert the numeric constant to floating-point */
   1.352 +         if (str2num(csa->image, &csa->value))
   1.353 +            error(csa, "numeric constant `%s' out of range\n",
   1.354 +               csa->image);
   1.355 +      }
   1.356 +      else if (csa->c == '+')
   1.357 +         csa->token = T_PLUS, add_char(csa);
   1.358 +      else if (csa->c == '-')
   1.359 +         csa->token = T_MINUS, add_char(csa);
   1.360 +      else if (csa->c == ':')
   1.361 +         csa->token = T_COLON, add_char(csa);
   1.362 +      else if (csa->c == '<')
   1.363 +      {  csa->token = T_LE, add_char(csa);
   1.364 +         if (csa->c == '=') add_char(csa);
   1.365 +      }
   1.366 +      else if (csa->c == '>')
   1.367 +      {  csa->token = T_GE, add_char(csa);
   1.368 +         if (csa->c == '=') add_char(csa);
   1.369 +      }
   1.370 +      else if (csa->c == '=')
   1.371 +      {  csa->token = T_EQ, add_char(csa);
   1.372 +         if (csa->c == '<')
   1.373 +            csa->token = T_LE, add_char(csa);
   1.374 +         else if (csa->c == '>')
   1.375 +            csa->token = T_GE, add_char(csa);
   1.376 +      }
   1.377 +      else
   1.378 +         error(csa, "character `%c' not recognized\n", csa->c);
   1.379 +      /* skip non-significant characters */
   1.380 +      while (csa->c == ' ') read_char(csa);
   1.381 +      return;
   1.382 +}
   1.383 +
   1.384 +static int find_col(struct csa *csa, char *name)
   1.385 +{     /* find column by its symbolic name */
   1.386 +      int j;
   1.387 +      j = glp_find_col(csa->P, name);
   1.388 +      if (j == 0)
   1.389 +      {  /* not found; create new column */
   1.390 +         j = glp_add_cols(csa->P, 1);
   1.391 +         glp_set_col_name(csa->P, j, name);
   1.392 +         /* enlarge working arrays, if necessary */
   1.393 +         if (csa->n_max < j)
   1.394 +         {  int n_max = csa->n_max;
   1.395 +            int *ind = csa->ind;
   1.396 +            double *val = csa->val;
   1.397 +            char *flag = csa->flag;
   1.398 +            double *lb = csa->lb;
   1.399 +            double *ub = csa->ub;
   1.400 +            csa->n_max += csa->n_max;
   1.401 +            csa->ind = xcalloc(1+csa->n_max, sizeof(int));
   1.402 +            memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int));
   1.403 +            xfree(ind);
   1.404 +            csa->val = xcalloc(1+csa->n_max, sizeof(double));
   1.405 +            memcpy(&csa->val[1], &val[1], n_max * sizeof(double));
   1.406 +            xfree(val);
   1.407 +            csa->flag = xcalloc(1+csa->n_max, sizeof(char));
   1.408 +            memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
   1.409 +            memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char));
   1.410 +            xfree(flag);
   1.411 +            csa->lb = xcalloc(1+csa->n_max, sizeof(double));
   1.412 +            memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double));
   1.413 +            xfree(lb);
   1.414 +            csa->ub = xcalloc(1+csa->n_max, sizeof(double));
   1.415 +            memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double));
   1.416 +            xfree(ub);
   1.417 +         }
   1.418 +         csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX;
   1.419 +      }
   1.420 +      return j;
   1.421 +}
   1.422 +
   1.423 +/***********************************************************************
   1.424 +*  parse_linear_form - parse linear form
   1.425 +*
   1.426 +*  This routine parses the linear form using the following syntax:
   1.427 +*
   1.428 +*  <variable> ::= <symbolic name>
   1.429 +*  <coefficient> ::= <numeric constant>
   1.430 +*  <term> ::= <variable> | <numeric constant> <variable>
   1.431 +*  <linear form> ::= <term> | + <term> | - <term> |
   1.432 +*     <linear form> + <term> | <linear form> - <term>
   1.433 +*
   1.434 +*  The routine returns the number of terms in the linear form. */
   1.435 +
   1.436 +static int parse_linear_form(struct csa *csa)
   1.437 +{     int j, k, len = 0, newlen;
   1.438 +      double s, coef;
   1.439 +loop: /* parse an optional sign */
   1.440 +      if (csa->token == T_PLUS)
   1.441 +         s = +1.0, scan_token(csa);
   1.442 +      else if (csa->token == T_MINUS)
   1.443 +         s = -1.0, scan_token(csa);
   1.444 +      else
   1.445 +         s = +1.0;
   1.446 +      /* parse an optional coefficient */
   1.447 +      if (csa->token == T_NUMBER)
   1.448 +         coef = csa->value, scan_token(csa);
   1.449 +      else
   1.450 +         coef = 1.0;
   1.451 +      /* parse a variable name */
   1.452 +      if (csa->token != T_NAME)
   1.453 +         error(csa, "missing variable name\n");
   1.454 +      /* find the corresponding column */
   1.455 +      j = find_col(csa, csa->image);
   1.456 +      /* check if the variable is already used in the linear form */
   1.457 +      if (csa->flag[j])
   1.458 +         error(csa, "multiple use of variable `%s' not allowed\n",
   1.459 +            csa->image);
   1.460 +      /* add new term to the linear form */
   1.461 +      len++, csa->ind[len] = j, csa->val[len] = s * coef;
   1.462 +      /* and mark that the variable is used in the linear form */
   1.463 +      csa->flag[j] = 1;
   1.464 +      scan_token(csa);
   1.465 +      /* if the next token is a sign, there is another term */
   1.466 +      if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop;
   1.467 +      /* clear marks of the variables used in the linear form */
   1.468 +      for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0;
   1.469 +      /* remove zero coefficients */
   1.470 +      newlen = 0;
   1.471 +      for (k = 1; k <= len; k++)
   1.472 +      {  if (csa->val[k] != 0.0)
   1.473 +         {  newlen++;
   1.474 +            csa->ind[newlen] = csa->ind[k];
   1.475 +            csa->val[newlen] = csa->val[k];
   1.476 +         }
   1.477 +      }
   1.478 +      return newlen;
   1.479 +}
   1.480 +
   1.481 +/***********************************************************************
   1.482 +*  parse_objective - parse objective function
   1.483 +*
   1.484 +*  This routine parses definition of the objective function using the
   1.485 +*  following syntax:
   1.486 +*
   1.487 +*  <obj sense> ::= minimize | minimum | min | maximize | maximum | max
   1.488 +*  <obj name> ::= <empty> | <symbolic name> :
   1.489 +*  <obj function> ::= <obj sense> <obj name> <linear form> */
   1.490 +
   1.491 +static void parse_objective(struct csa *csa)
   1.492 +{     /* parse objective sense */
   1.493 +      int k, len;
   1.494 +      /* parse the keyword 'minimize' or 'maximize' */
   1.495 +      if (csa->token == T_MINIMIZE)
   1.496 +         glp_set_obj_dir(csa->P, GLP_MIN);
   1.497 +      else if (csa->token == T_MAXIMIZE)
   1.498 +         glp_set_obj_dir(csa->P, GLP_MAX);
   1.499 +      else
   1.500 +         xassert(csa != csa);
   1.501 +      scan_token(csa);
   1.502 +      /* parse objective name */
   1.503 +      if (csa->token == T_NAME && csa->c == ':')
   1.504 +      {  /* objective name is followed by a colon */
   1.505 +         glp_set_obj_name(csa->P, csa->image);
   1.506 +         scan_token(csa);
   1.507 +         xassert(csa->token == T_COLON);
   1.508 +         scan_token(csa);
   1.509 +      }
   1.510 +      else
   1.511 +      {  /* objective name is not specified; use default */
   1.512 +         glp_set_obj_name(csa->P, "obj");
   1.513 +      }
   1.514 +      /* parse linear form */
   1.515 +      len = parse_linear_form(csa);
   1.516 +      for (k = 1; k <= len; k++)
   1.517 +         glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]);
   1.518 +      return;
   1.519 +}
   1.520 +
   1.521 +/***********************************************************************
   1.522 +*  parse_constraints - parse constraints section
   1.523 +*
   1.524 +*  This routine parses the constraints section using the following
   1.525 +*  syntax:
   1.526 +*
   1.527 +*  <row name> ::= <empty> | <symbolic name> :
   1.528 +*  <row sense> ::= < | <= | =< | > | >= | => | =
   1.529 +*  <right-hand side> ::= <numeric constant> | + <numeric constant> |
   1.530 +*     - <numeric constant>
   1.531 +*  <constraint> ::= <row name> <linear form> <row sense>
   1.532 +*     <right-hand side>
   1.533 +*  <subject to> ::= subject to | such that | st | s.t. | st.
   1.534 +*  <constraints section> ::= <subject to> <constraint> |
   1.535 +*     <constraints section> <constraint> */
   1.536 +
   1.537 +static void parse_constraints(struct csa *csa)
   1.538 +{     int i, len, type;
   1.539 +      double s;
   1.540 +      /* parse the keyword 'subject to' */
   1.541 +      xassert(csa->token == T_SUBJECT_TO);
   1.542 +      scan_token(csa);
   1.543 +loop: /* create new row (constraint) */
   1.544 +      i = glp_add_rows(csa->P, 1);
   1.545 +      /* parse row name */
   1.546 +      if (csa->token == T_NAME && csa->c == ':')
   1.547 +      {  /* row name is followed by a colon */
   1.548 +         if (glp_find_row(csa->P, csa->image) != 0)
   1.549 +            error(csa, "constraint `%s' multiply defined\n",
   1.550 +               csa->image);
   1.551 +         glp_set_row_name(csa->P, i, csa->image);
   1.552 +         scan_token(csa);
   1.553 +         xassert(csa->token == T_COLON);
   1.554 +         scan_token(csa);
   1.555 +      }
   1.556 +      else
   1.557 +      {  /* row name is not specified; use default */
   1.558 +         char name[50];
   1.559 +         sprintf(name, "r.%d", csa->count);
   1.560 +         glp_set_row_name(csa->P, i, name);
   1.561 +      }
   1.562 +      /* parse linear form */
   1.563 +      len = parse_linear_form(csa);
   1.564 +      glp_set_mat_row(csa->P, i, len, csa->ind, csa->val);
   1.565 +      /* parse constraint sense */
   1.566 +      if (csa->token == T_LE)
   1.567 +         type = GLP_UP, scan_token(csa);
   1.568 +      else if (csa->token == T_GE)
   1.569 +         type = GLP_LO, scan_token(csa);
   1.570 +      else if (csa->token == T_EQ)
   1.571 +         type = GLP_FX, scan_token(csa);
   1.572 +      else
   1.573 +         error(csa, "missing constraint sense\n");
   1.574 +      /* parse right-hand side */
   1.575 +      if (csa->token == T_PLUS)
   1.576 +         s = +1.0, scan_token(csa);
   1.577 +      else if (csa->token == T_MINUS)
   1.578 +         s = -1.0, scan_token(csa);
   1.579 +      else
   1.580 +         s = +1.0;
   1.581 +      if (csa->token != T_NUMBER)
   1.582 +         error(csa, "missing right-hand side\n");
   1.583 +      glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value);
   1.584 +      /* the rest of the current line must be empty */
   1.585 +      if (!(csa->c == '\n' || csa->c == XEOF))
   1.586 +         error(csa, "invalid symbol(s) beyond right-hand side\n");
   1.587 +      scan_token(csa);
   1.588 +      /* if the next token is a sign, numeric constant, or a symbolic
   1.589 +         name, here is another constraint */
   1.590 +      if (csa->token == T_PLUS || csa->token == T_MINUS ||
   1.591 +          csa->token == T_NUMBER || csa->token == T_NAME) goto loop;
   1.592 +      return;
   1.593 +}
   1.594 +
   1.595 +static void set_lower_bound(struct csa *csa, int j, double lb)
   1.596 +{     /* set lower bound of j-th variable */
   1.597 +      if (csa->lb[j] != +DBL_MAX)
   1.598 +      {  warning(csa, "lower bound of variable `%s' redefined\n",
   1.599 +            glp_get_col_name(csa->P, j));
   1.600 +      }
   1.601 +      csa->lb[j] = lb;
   1.602 +      return;
   1.603 +}
   1.604 +
   1.605 +static void set_upper_bound(struct csa *csa, int j, double ub)
   1.606 +{     /* set upper bound of j-th variable */
   1.607 +      if (csa->ub[j] != -DBL_MAX)
   1.608 +      {  warning(csa, "upper bound of variable `%s' redefined\n",
   1.609 +            glp_get_col_name(csa->P, j));
   1.610 +      }
   1.611 +      csa->ub[j] = ub;
   1.612 +      return;
   1.613 +}
   1.614 +
   1.615 +/***********************************************************************
   1.616 +*  parse_bounds - parse bounds section
   1.617 +*
   1.618 +*  This routine parses the bounds section using the following syntax:
   1.619 +*
   1.620 +*  <variable> ::= <symbolic name>
   1.621 +*  <infinity> ::= infinity | inf
   1.622 +*  <bound> ::= <numeric constant> | + <numeric constant> |
   1.623 +*     - <numeric constant> | + <infinity> | - <infinity>
   1.624 +*  <lt> ::= < | <= | =<
   1.625 +*  <gt> ::= > | >= | =>
   1.626 +*  <bound definition> ::= <bound> <lt> <variable> <lt> <bound> |
   1.627 +*     <bound> <lt> <variable> | <variable> <lt> <bound> |
   1.628 +*     <variable> <gt> <bound> | <variable> = <bound> | <variable> free
   1.629 +*  <bounds> ::= bounds | bound
   1.630 +*  <bounds section> ::= <bounds> |
   1.631 +*     <bounds section> <bound definition> */
   1.632 +
   1.633 +static void parse_bounds(struct csa *csa)
   1.634 +{     int j, lb_flag;
   1.635 +      double lb, s;
   1.636 +      /* parse the keyword 'bounds' */
   1.637 +      xassert(csa->token == T_BOUNDS);
   1.638 +      scan_token(csa);
   1.639 +loop: /* bound definition can start with a sign, numeric constant, or
   1.640 +         a symbolic name */
   1.641 +      if (!(csa->token == T_PLUS || csa->token == T_MINUS ||
   1.642 +            csa->token == T_NUMBER || csa->token == T_NAME)) goto done;
   1.643 +      /* parse bound definition */
   1.644 +      if (csa->token == T_PLUS || csa->token == T_MINUS)
   1.645 +      {  /* parse signed lower bound */
   1.646 +         lb_flag = 1;
   1.647 +         s = (csa->token == T_PLUS ? +1.0 : -1.0);
   1.648 +         scan_token(csa);
   1.649 +         if (csa->token == T_NUMBER)
   1.650 +            lb = s * csa->value, scan_token(csa);
   1.651 +         else if (the_same(csa->image, "infinity") ||
   1.652 +                  the_same(csa->image, "inf"))
   1.653 +         {  if (s > 0.0)
   1.654 +               error(csa, "invalid use of `+inf' as lower bound\n");
   1.655 +            lb = -DBL_MAX, scan_token(csa);
   1.656 +         }
   1.657 +         else
   1.658 +            error(csa, "missing lower bound\n");
   1.659 +      }
   1.660 +      else if (csa->token == T_NUMBER)
   1.661 +      {  /* parse unsigned lower bound */
   1.662 +         lb_flag = 1;
   1.663 +         lb = csa->value, scan_token(csa);
   1.664 +      }
   1.665 +      else
   1.666 +      {  /* lower bound is not specified */
   1.667 +         lb_flag = 0;
   1.668 +      }
   1.669 +      /* parse the token that should follow the lower bound */
   1.670 +      if (lb_flag)
   1.671 +      {  if (csa->token != T_LE)
   1.672 +            error(csa, "missing `<', `<=', or `=<' after lower bound\n")
   1.673 +               ;
   1.674 +         scan_token(csa);
   1.675 +      }
   1.676 +      /* parse variable name */
   1.677 +      if (csa->token != T_NAME)
   1.678 +         error(csa, "missing variable name\n");
   1.679 +      j = find_col(csa, csa->image);
   1.680 +      /* set lower bound */
   1.681 +      if (lb_flag) set_lower_bound(csa, j, lb);
   1.682 +      scan_token(csa);
   1.683 +      /* parse the context that follows the variable name */
   1.684 +      if (csa->token == T_LE)
   1.685 +      {  /* parse upper bound */
   1.686 +         scan_token(csa);
   1.687 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
   1.688 +         {  /* parse signed upper bound */
   1.689 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
   1.690 +            scan_token(csa);
   1.691 +            if (csa->token == T_NUMBER)
   1.692 +            {  set_upper_bound(csa, j, s * csa->value);
   1.693 +               scan_token(csa);
   1.694 +            }
   1.695 +            else if (the_same(csa->image, "infinity") ||
   1.696 +                     the_same(csa->image, "inf"))
   1.697 +            {  if (s < 0.0)
   1.698 +                  error(csa, "invalid use of `-inf' as upper bound\n");
   1.699 +               set_upper_bound(csa, j, +DBL_MAX);
   1.700 +               scan_token(csa);
   1.701 +            }
   1.702 +            else
   1.703 +               error(csa, "missing upper bound\n");
   1.704 +         }
   1.705 +         else if (csa->token == T_NUMBER)
   1.706 +         {  /* parse unsigned upper bound */
   1.707 +            set_upper_bound(csa, j, csa->value);
   1.708 +            scan_token(csa);
   1.709 +         }
   1.710 +         else
   1.711 +            error(csa, "missing upper bound\n");
   1.712 +      }
   1.713 +      else if (csa->token == T_GE)
   1.714 +      {  /* parse lower bound */
   1.715 +         if (lb_flag)
   1.716 +         {  /* the context '... <= x >= ...' is invalid */
   1.717 +            error(csa, "invalid bound definition\n");
   1.718 +         }
   1.719 +         scan_token(csa);
   1.720 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
   1.721 +         {  /* parse signed lower bound */
   1.722 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
   1.723 +            scan_token(csa);
   1.724 +            if (csa->token == T_NUMBER)
   1.725 +            {  set_lower_bound(csa, j, s * csa->value);
   1.726 +               scan_token(csa);
   1.727 +            }
   1.728 +            else if (the_same(csa->image, "infinity") ||
   1.729 +                     the_same(csa->image, "inf") == 0)
   1.730 +            {  if (s > 0.0)
   1.731 +                  error(csa, "invalid use of `+inf' as lower bound\n");
   1.732 +               set_lower_bound(csa, j, -DBL_MAX);
   1.733 +               scan_token(csa);
   1.734 +            }
   1.735 +            else
   1.736 +               error(csa, "missing lower bound\n");
   1.737 +         }
   1.738 +         else if (csa->token == T_NUMBER)
   1.739 +         {  /* parse unsigned lower bound */
   1.740 +            set_lower_bound(csa, j, csa->value);
   1.741 +            scan_token(csa);
   1.742 +         }
   1.743 +         else
   1.744 +            error(csa, "missing lower bound\n");
   1.745 +      }
   1.746 +      else if (csa->token == T_EQ)
   1.747 +      {  /* parse fixed value */
   1.748 +         if (lb_flag)
   1.749 +         {  /* the context '... <= x = ...' is invalid */
   1.750 +            error(csa, "invalid bound definition\n");
   1.751 +         }
   1.752 +         scan_token(csa);
   1.753 +         if (csa->token == T_PLUS || csa->token == T_MINUS)
   1.754 +         {  /* parse signed fixed value */
   1.755 +            s = (csa->token == T_PLUS ? +1.0 : -1.0);
   1.756 +            scan_token(csa);
   1.757 +            if (csa->token == T_NUMBER)
   1.758 +            {  set_lower_bound(csa, j, s * csa->value);
   1.759 +               set_upper_bound(csa, j, s * csa->value);
   1.760 +               scan_token(csa);
   1.761 +            }
   1.762 +            else
   1.763 +               error(csa, "missing fixed value\n");
   1.764 +         }
   1.765 +         else if (csa->token == T_NUMBER)
   1.766 +         {  /* parse unsigned fixed value */
   1.767 +            set_lower_bound(csa, j, csa->value);
   1.768 +            set_upper_bound(csa, j, csa->value);
   1.769 +            scan_token(csa);
   1.770 +         }
   1.771 +         else
   1.772 +            error(csa, "missing fixed value\n");
   1.773 +      }
   1.774 +      else if (the_same(csa->image, "free"))
   1.775 +      {  /* parse the keyword 'free' */
   1.776 +         if (lb_flag)
   1.777 +         {  /* the context '... <= x free ...' is invalid */
   1.778 +            error(csa, "invalid bound definition\n");
   1.779 +         }
   1.780 +         set_lower_bound(csa, j, -DBL_MAX);
   1.781 +         set_upper_bound(csa, j, +DBL_MAX);
   1.782 +         scan_token(csa);
   1.783 +      }
   1.784 +      else if (!lb_flag)
   1.785 +      {  /* neither lower nor upper bounds are specified */
   1.786 +         error(csa, "invalid bound definition\n");
   1.787 +      }
   1.788 +      goto loop;
   1.789 +done: return;
   1.790 +}
   1.791 +
   1.792 +/***********************************************************************
   1.793 +*  parse_integer - parse general, integer, or binary section
   1.794 +*
   1.795 +*  <variable> ::= <symbolic name>
   1.796 +*  <general> ::= general | generals | gen
   1.797 +*  <integer> ::= integer | integers | int
   1.798 +*  <binary> ::= binary | binaries | bin
   1.799 +*  <section head> ::= <general> <integer> <binary>
   1.800 +*  <additional section> ::= <section head> |
   1.801 +*     <additional section> <variable> */
   1.802 +
   1.803 +static void parse_integer(struct csa *csa)
   1.804 +{     int j, binary;
   1.805 +      /* parse the keyword 'general', 'integer', or 'binary' */
   1.806 +      if (csa->token == T_GENERAL)
   1.807 +         binary = 0, scan_token(csa);
   1.808 +      else if (csa->token == T_INTEGER)
   1.809 +         binary = 0, scan_token(csa);
   1.810 +      else if (csa->token == T_BINARY)
   1.811 +         binary = 1, scan_token(csa);
   1.812 +      else
   1.813 +         xassert(csa != csa);
   1.814 +      /* parse list of variables (may be empty) */
   1.815 +      while (csa->token == T_NAME)
   1.816 +      {  /* find the corresponding column */
   1.817 +         j = find_col(csa, csa->image);
   1.818 +         /* change kind of the variable */
   1.819 +         glp_set_col_kind(csa->P, j, GLP_IV);
   1.820 +         /* set 0-1 bounds for the binary variable */
   1.821 +         if (binary)
   1.822 +         {  set_lower_bound(csa, j, 0.0);
   1.823 +            set_upper_bound(csa, j, 1.0);
   1.824 +         }
   1.825 +         scan_token(csa);
   1.826 +      }
   1.827 +      return;
   1.828 +}
   1.829 +
   1.830 +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
   1.831 +{     /* read problem data in CPLEX LP format */
   1.832 +      glp_cpxcp _parm;
   1.833 +      struct csa _csa, *csa = &_csa;
   1.834 +      int ret;
   1.835 +      xprintf("Reading problem data from `%s'...\n", fname);
   1.836 +      if (parm == NULL)
   1.837 +         glp_init_cpxcp(&_parm), parm = &_parm;
   1.838 +      /* check control parameters */
   1.839 +      check_parm("glp_read_lp", parm);
   1.840 +      /* initialize common storage area */
   1.841 +      csa->P = P;
   1.842 +      csa->parm = parm;
   1.843 +      csa->fname = fname;
   1.844 +      csa->fp = NULL;
   1.845 +      if (setjmp(csa->jump))
   1.846 +      {  ret = 1;
   1.847 +         goto done;
   1.848 +      }
   1.849 +      csa->count = 0;
   1.850 +      csa->c = '\n';
   1.851 +      csa->token = T_EOF;
   1.852 +      csa->image[0] = '\0';
   1.853 +      csa->imlen = 0;
   1.854 +      csa->value = 0.0;
   1.855 +      csa->n_max = 100;
   1.856 +      csa->ind = xcalloc(1+csa->n_max, sizeof(int));
   1.857 +      csa->val = xcalloc(1+csa->n_max, sizeof(double));
   1.858 +      csa->flag = xcalloc(1+csa->n_max, sizeof(char));
   1.859 +      memset(&csa->flag[1], 0, csa->n_max * sizeof(char));
   1.860 +      csa->lb = xcalloc(1+csa->n_max, sizeof(double));
   1.861 +      csa->ub = xcalloc(1+csa->n_max, sizeof(double));
   1.862 +      /* erase problem object */
   1.863 +      glp_erase_prob(P);
   1.864 +      glp_create_index(P);
   1.865 +      /* open input CPLEX LP file */
   1.866 +      csa->fp = xfopen(fname, "r");
   1.867 +      if (csa->fp == NULL)
   1.868 +      {  xprintf("Unable to open `%s' - %s\n", fname, xerrmsg());
   1.869 +         ret = 1;
   1.870 +         goto done;
   1.871 +      }
   1.872 +      /* scan very first token */
   1.873 +      scan_token(csa);
   1.874 +      /* parse definition of the objective function */
   1.875 +      if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE))
   1.876 +         error(csa, "`minimize' or `maximize' keyword missing\n");
   1.877 +      parse_objective(csa);
   1.878 +      /* parse constraints section */
   1.879 +      if (csa->token != T_SUBJECT_TO)
   1.880 +         error(csa, "constraints section missing\n");
   1.881 +      parse_constraints(csa);
   1.882 +      /* parse optional bounds section */
   1.883 +      if (csa->token == T_BOUNDS) parse_bounds(csa);
   1.884 +      /* parse optional general, integer, and binary sections */
   1.885 +      while (csa->token == T_GENERAL ||
   1.886 +             csa->token == T_INTEGER ||
   1.887 +             csa->token == T_BINARY) parse_integer(csa);
   1.888 +      /* check for the keyword 'end' */
   1.889 +      if (csa->token == T_END)
   1.890 +         scan_token(csa);
   1.891 +      else if (csa->token == T_EOF)
   1.892 +         warning(csa, "keyword `end' missing\n");
   1.893 +      else
   1.894 +         error(csa, "symbol `%s' in wrong position\n", csa->image);
   1.895 +      /* nothing must follow the keyword 'end' (except comments) */
   1.896 +      if (csa->token != T_EOF)
   1.897 +         error(csa, "extra symbol(s) detected beyond `end'\n");
   1.898 +      /* set bounds of variables */
   1.899 +      {  int j, type;
   1.900 +         double lb, ub;
   1.901 +         for (j = 1; j <= P->n; j++)
   1.902 +         {  lb = csa->lb[j];
   1.903 +            ub = csa->ub[j];
   1.904 +            if (lb == +DBL_MAX) lb = 0.0;      /* default lb */
   1.905 +            if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */
   1.906 +            if (lb == -DBL_MAX && ub == +DBL_MAX)
   1.907 +               type = GLP_FR;
   1.908 +            else if (ub == +DBL_MAX)
   1.909 +               type = GLP_LO;
   1.910 +            else if (lb == -DBL_MAX)
   1.911 +               type = GLP_UP;
   1.912 +            else if (lb != ub)
   1.913 +               type = GLP_DB;
   1.914 +            else
   1.915 +               type = GLP_FX;
   1.916 +            glp_set_col_bnds(csa->P, j, type, lb, ub);
   1.917 +         }
   1.918 +      }
   1.919 +      /* print some statistics */
   1.920 +      xprintf("%d row%s, %d column%s, %d non-zero%s\n",
   1.921 +         P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s",
   1.922 +         P->nnz, P->nnz == 1 ? "" : "s");
   1.923 +      if (glp_get_num_int(P) > 0)
   1.924 +      {  int ni = glp_get_num_int(P);
   1.925 +         int nb = glp_get_num_bin(P);
   1.926 +         if (ni == 1)
   1.927 +         {  if (nb == 0)
   1.928 +               xprintf("One variable is integer\n");
   1.929 +            else
   1.930 +               xprintf("One variable is binary\n");
   1.931 +         }
   1.932 +         else
   1.933 +         {  xprintf("%d integer variables, ", ni);
   1.934 +            if (nb == 0)
   1.935 +               xprintf("none");
   1.936 +            else if (nb == 1)
   1.937 +               xprintf("one");
   1.938 +            else if (nb == ni)
   1.939 +               xprintf("all");
   1.940 +            else
   1.941 +               xprintf("%d", nb);
   1.942 +            xprintf(" of which %s binary\n", nb == 1 ? "is" : "are");
   1.943 +         }
   1.944 +      }
   1.945 +      xprintf("%d lines were read\n", csa->count);
   1.946 +      /* problem data has been successfully read */
   1.947 +      glp_delete_index(P);
   1.948 +      glp_sort_matrix(P);
   1.949 +      ret = 0;
   1.950 +done: if (csa->fp != NULL) xfclose(csa->fp);
   1.951 +      xfree(csa->ind);
   1.952 +      xfree(csa->val);
   1.953 +      xfree(csa->flag);
   1.954 +      xfree(csa->lb);
   1.955 +      xfree(csa->ub);
   1.956 +      if (ret != 0) glp_erase_prob(P);
   1.957 +      return ret;
   1.958 +}
   1.959 +
   1.960 +/***********************************************************************
   1.961 +*  NAME
   1.962 +*
   1.963 +*  glp_write_lp - write problem data in CPLEX LP format
   1.964 +*
   1.965 +*  SYNOPSIS
   1.966 +*
   1.967 +*  int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char
   1.968 +*     *fname);
   1.969 +*
   1.970 +*  DESCRIPTION
   1.971 +*
   1.972 +*  The routine glp_write_lp writes problem data in CPLEX LP format to
   1.973 +*  a text file.
   1.974 +*
   1.975 +*  The parameter parm is a pointer to the structure glp_cpxcp, which
   1.976 +*  specifies control parameters used by the routine. If parm is NULL,
   1.977 +*  the routine uses default settings.
   1.978 +*
   1.979 +*  The character string fname specifies a name of the text file to be
   1.980 +*  written.
   1.981 +*
   1.982 +*  RETURNS
   1.983 +*
   1.984 +*  If the operation was successful, the routine glp_write_lp returns
   1.985 +*  zero. Otherwise, it prints an error message and returns non-zero. */
   1.986 +
   1.987 +#define csa csa1
   1.988 +
   1.989 +struct csa
   1.990 +{     /* common storage area */
   1.991 +      glp_prob *P;
   1.992 +      /* pointer to problem object */
   1.993 +      const glp_cpxcp *parm;
   1.994 +      /* pointer to control parameters */
   1.995 +};
   1.996 +
   1.997 +static int check_name(char *name)
   1.998 +{     /* check if specified name is valid for CPLEX LP format */
   1.999 +      if (*name == '.') return 1;
  1.1000 +      if (isdigit((unsigned char)*name)) return 1;
  1.1001 +      for (; *name; name++)
  1.1002 +      {  if (!isalnum((unsigned char)*name) &&
  1.1003 +             strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1;
  1.1004 +      }
  1.1005 +      return 0; /* name is ok */
  1.1006 +}
  1.1007 +
  1.1008 +static void adjust_name(char *name)
  1.1009 +{     /* attempt to adjust specified name to make it valid for CPLEX LP
  1.1010 +         format */
  1.1011 +      for (; *name; name++)
  1.1012 +      {  if (*name == ' ')
  1.1013 +            *name = '_';
  1.1014 +         else if (*name == '-')
  1.1015 +            *name = '~';
  1.1016 +         else if (*name == '[')
  1.1017 +            *name = '(';
  1.1018 +         else if (*name == ']')
  1.1019 +            *name = ')';
  1.1020 +      }
  1.1021 +      return;
  1.1022 +}
  1.1023 +
  1.1024 +static char *row_name(struct csa *csa, int i, char rname[255+1])
  1.1025 +{     /* construct symbolic name of i-th row (constraint) */
  1.1026 +      const char *name;
  1.1027 +      if (i == 0)
  1.1028 +         name = glp_get_obj_name(csa->P);
  1.1029 +      else
  1.1030 +         name = glp_get_row_name(csa->P, i);
  1.1031 +      if (name == NULL) goto fake;
  1.1032 +      strcpy(rname, name);
  1.1033 +      adjust_name(rname);
  1.1034 +      if (check_name(rname)) goto fake;
  1.1035 +      return rname;
  1.1036 +fake: if (i == 0)
  1.1037 +         strcpy(rname, "obj");
  1.1038 +      else
  1.1039 +         sprintf(rname, "r_%d", i);
  1.1040 +      return rname;
  1.1041 +}
  1.1042 +
  1.1043 +static char *col_name(struct csa *csa, int j, char cname[255+1])
  1.1044 +{     /* construct symbolic name of j-th column (variable) */
  1.1045 +      const char *name;
  1.1046 +      name = glp_get_col_name(csa->P, j);
  1.1047 +      if (name == NULL) goto fake;
  1.1048 +      strcpy(cname, name);
  1.1049 +      adjust_name(cname);
  1.1050 +      if (check_name(cname)) goto fake;
  1.1051 +      return cname;
  1.1052 +fake: sprintf(cname, "x_%d", j);
  1.1053 +      return cname;
  1.1054 +}
  1.1055 +
  1.1056 +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname)
  1.1057 +{     /* write problem data in CPLEX LP format */
  1.1058 +      glp_cpxcp _parm;
  1.1059 +      struct csa _csa, *csa = &_csa;
  1.1060 +      XFILE *fp;
  1.1061 +      GLPROW *row;
  1.1062 +      GLPCOL *col;
  1.1063 +      GLPAIJ *aij;
  1.1064 +      int i, j, len, flag, count, ret;
  1.1065 +      char line[1000+1], term[500+1], name[255+1];
  1.1066 +      xprintf("Writing problem data to `%s'...\n", fname);
  1.1067 +      if (parm == NULL)
  1.1068 +         glp_init_cpxcp(&_parm), parm = &_parm;
  1.1069 +      /* check control parameters */
  1.1070 +      check_parm("glp_write_lp", parm);
  1.1071 +      /* initialize common storage area */
  1.1072 +      csa->P = P;
  1.1073 +      csa->parm = parm;
  1.1074 +      /* create output CPLEX LP file */
  1.1075 +      fp = xfopen(fname, "w"), count = 0;
  1.1076 +      if (fp == NULL)
  1.1077 +      {  xprintf("Unable to create `%s' - %s\n", fname, xerrmsg());
  1.1078 +         ret = 1;
  1.1079 +         goto done;
  1.1080 +      }
  1.1081 +      /* write problem name */
  1.1082 +      xfprintf(fp, "\\* Problem: %s *\\\n",
  1.1083 +         P->name == NULL ? "Unknown" : P->name), count++;
  1.1084 +      xfprintf(fp, "\n"), count++;
  1.1085 +      /* the problem should contain at least one row and one column */
  1.1086 +      if (!(P->m > 0 && P->n > 0))
  1.1087 +      {  xprintf("Warning: problem has no rows/columns\n");
  1.1088 +         xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"),
  1.1089 +            count++;
  1.1090 +         xfprintf(fp, "\n"), count++;
  1.1091 +         goto skip;
  1.1092 +      }
  1.1093 +      /* write the objective function definition */
  1.1094 +      if (P->dir == GLP_MIN)
  1.1095 +         xfprintf(fp, "Minimize\n"), count++;
  1.1096 +      else if (P->dir == GLP_MAX)
  1.1097 +         xfprintf(fp, "Maximize\n"), count++;
  1.1098 +      else
  1.1099 +         xassert(P != P);
  1.1100 +      row_name(csa, 0, name);
  1.1101 +      sprintf(line, " %s:", name);
  1.1102 +      len = 0;
  1.1103 +      for (j = 1; j <= P->n; j++)
  1.1104 +      {  col = P->col[j];
  1.1105 +         if (col->coef != 0.0 || col->ptr == NULL)
  1.1106 +         {  len++;
  1.1107 +            col_name(csa, j, name);
  1.1108 +            if (col->coef == 0.0)
  1.1109 +               sprintf(term, " + 0 %s", name); /* empty column */
  1.1110 +            else if (col->coef == +1.0)
  1.1111 +               sprintf(term, " + %s", name);
  1.1112 +            else if (col->coef == -1.0)
  1.1113 +               sprintf(term, " - %s", name);
  1.1114 +            else if (col->coef > 0.0)
  1.1115 +               sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name);
  1.1116 +            else
  1.1117 +               sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name);
  1.1118 +            if (strlen(line) + strlen(term) > 72)
  1.1119 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
  1.1120 +            strcat(line, term);
  1.1121 +         }
  1.1122 +      }
  1.1123 +      if (len == 0)
  1.1124 +      {  /* empty objective */
  1.1125 +         sprintf(term, " 0 %s", col_name(csa, 1, name));
  1.1126 +         strcat(line, term);
  1.1127 +      }
  1.1128 +      xfprintf(fp, "%s\n", line), count++;
  1.1129 +      if (P->c0 != 0.0)
  1.1130 +         xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0),
  1.1131 +            count++;
  1.1132 +      xfprintf(fp, "\n"), count++;
  1.1133 +      /* write the constraints section */
  1.1134 +      xfprintf(fp, "Subject To\n"), count++;
  1.1135 +      for (i = 1; i <= P->m; i++)
  1.1136 +      {  row = P->row[i];
  1.1137 +         if (row->type == GLP_FR) continue; /* skip free row */
  1.1138 +         row_name(csa, i, name);
  1.1139 +         sprintf(line, " %s:", name);
  1.1140 +         /* linear form */
  1.1141 +         for (aij = row->ptr; aij != NULL; aij = aij->r_next)
  1.1142 +         {  col_name(csa, aij->col->j, name);
  1.1143 +            if (aij->val == +1.0)
  1.1144 +               sprintf(term, " + %s", name);
  1.1145 +            else if (aij->val == -1.0)
  1.1146 +               sprintf(term, " - %s", name);
  1.1147 +            else if (aij->val > 0.0)
  1.1148 +               sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name);
  1.1149 +            else
  1.1150 +               sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name);
  1.1151 +            if (strlen(line) + strlen(term) > 72)
  1.1152 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
  1.1153 +            strcat(line, term);
  1.1154 +         }
  1.1155 +         if (row->type == GLP_DB)
  1.1156 +         {  /* double-bounded (ranged) constraint */
  1.1157 +            sprintf(term, " - ~r_%d", i);
  1.1158 +            if (strlen(line) + strlen(term) > 72)
  1.1159 +               xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
  1.1160 +            strcat(line, term);
  1.1161 +         }
  1.1162 +         else if (row->ptr == NULL)
  1.1163 +         {  /* empty constraint */
  1.1164 +            sprintf(term, " 0 %s", col_name(csa, 1, name));
  1.1165 +            strcat(line, term);
  1.1166 +         }
  1.1167 +         /* right hand-side */
  1.1168 +         if (row->type == GLP_LO)
  1.1169 +            sprintf(term, " >= %.*g", DBL_DIG, row->lb);
  1.1170 +         else if (row->type == GLP_UP)
  1.1171 +            sprintf(term, " <= %.*g", DBL_DIG, row->ub);
  1.1172 +         else if (row->type == GLP_DB || row->type == GLP_FX)
  1.1173 +            sprintf(term, " = %.*g", DBL_DIG, row->lb);
  1.1174 +         else
  1.1175 +            xassert(row != row);
  1.1176 +         if (strlen(line) + strlen(term) > 72)
  1.1177 +            xfprintf(fp, "%s\n", line), line[0] = '\0', count++;
  1.1178 +         strcat(line, term);
  1.1179 +         xfprintf(fp, "%s\n", line), count++;
  1.1180 +      }
  1.1181 +      xfprintf(fp, "\n"), count++;
  1.1182 +      /* write the bounds section */
  1.1183 +      flag = 0;
  1.1184 +      for (i = 1; i <= P->m; i++)
  1.1185 +      {  row = P->row[i];
  1.1186 +         if (row->type != GLP_DB) continue;
  1.1187 +         if (!flag)
  1.1188 +            xfprintf(fp, "Bounds\n"), flag = 1, count++;
  1.1189 +         xfprintf(fp, " 0 <= ~r_%d <= %.*g\n",
  1.1190 +            i, DBL_DIG, row->ub - row->lb), count++;
  1.1191 +      }
  1.1192 +      for (j = 1; j <= P->n; j++)
  1.1193 +      {  col = P->col[j];
  1.1194 +         if (col->type == GLP_LO && col->lb == 0.0) continue;
  1.1195 +         if (!flag)
  1.1196 +            xfprintf(fp, "Bounds\n"), flag = 1, count++;
  1.1197 +         col_name(csa, j, name);
  1.1198 +         if (col->type == GLP_FR)
  1.1199 +            xfprintf(fp, " %s free\n", name), count++;
  1.1200 +         else if (col->type == GLP_LO)
  1.1201 +            xfprintf(fp, " %s >= %.*g\n",
  1.1202 +               name, DBL_DIG, col->lb), count++;
  1.1203 +         else if (col->type == GLP_UP)
  1.1204 +            xfprintf(fp, " -Inf <= %s <= %.*g\n",
  1.1205 +               name, DBL_DIG, col->ub), count++;
  1.1206 +         else if (col->type == GLP_DB)
  1.1207 +            xfprintf(fp, " %.*g <= %s <= %.*g\n",
  1.1208 +               DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++;
  1.1209 +         else if (col->type == GLP_FX)
  1.1210 +            xfprintf(fp, " %s = %.*g\n",
  1.1211 +               name, DBL_DIG, col->lb), count++;
  1.1212 +         else
  1.1213 +            xassert(col != col);
  1.1214 +      }
  1.1215 +      if (flag) xfprintf(fp, "\n"), count++;
  1.1216 +      /* write the integer section */
  1.1217 +      flag = 0;
  1.1218 +      for (j = 1; j <= P->n; j++)
  1.1219 +      {  col = P->col[j];
  1.1220 +         if (col->kind == GLP_CV) continue;
  1.1221 +         xassert(col->kind == GLP_IV);
  1.1222 +         if (!flag)
  1.1223 +            xfprintf(fp, "Generals\n"), flag = 1, count++;
  1.1224 +         xfprintf(fp, " %s\n", col_name(csa, j, name)), count++;
  1.1225 +      }
  1.1226 +      if (flag) xfprintf(fp, "\n"), count++;
  1.1227 +skip: /* write the end keyword */
  1.1228 +      xfprintf(fp, "End\n"), count++;
  1.1229 +      xfflush(fp);
  1.1230 +      if (xferror(fp))
  1.1231 +      {  xprintf("Write error on `%s' - %s\n", fname, xerrmsg());
  1.1232 +         ret = 1;
  1.1233 +         goto done;
  1.1234 +      }
  1.1235 +      /* problem data has been successfully written */
  1.1236 +      xprintf("%d lines were written\n", count);
  1.1237 +      ret = 0;
  1.1238 +done: if (fp != NULL) xfclose(fp);
  1.1239 +      return ret;
  1.1240 +}
  1.1241 +
  1.1242 +/* eof */