src/glpmpl04.c
author Alpar Juttner <alpar@cs.elte.hu>
Mon, 06 Dec 2010 13:09:21 +0100
changeset 1 c445c931472f
permissions -rw-r--r--
Import glpk-4.45

- Generated files and doc/notes are removed
alpar@1
     1
/* glpmpl04.c */
alpar@1
     2
alpar@1
     3
/***********************************************************************
alpar@1
     4
*  This code is part of GLPK (GNU Linear Programming Kit).
alpar@1
     5
*
alpar@1
     6
*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
alpar@1
     7
*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
alpar@1
     8
*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
alpar@1
     9
*  E-mail: <mao@gnu.org>.
alpar@1
    10
*
alpar@1
    11
*  GLPK is free software: you can redistribute it and/or modify it
alpar@1
    12
*  under the terms of the GNU General Public License as published by
alpar@1
    13
*  the Free Software Foundation, either version 3 of the License, or
alpar@1
    14
*  (at your option) any later version.
alpar@1
    15
*
alpar@1
    16
*  GLPK is distributed in the hope that it will be useful, but WITHOUT
alpar@1
    17
*  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
alpar@1
    18
*  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
alpar@1
    19
*  License for more details.
alpar@1
    20
*
alpar@1
    21
*  You should have received a copy of the GNU General Public License
alpar@1
    22
*  along with GLPK. If not, see <http://www.gnu.org/licenses/>.
alpar@1
    23
***********************************************************************/
alpar@1
    24
alpar@1
    25
#define _GLPSTD_ERRNO
alpar@1
    26
#define _GLPSTD_STDIO
alpar@1
    27
#include "glpmpl.h"
alpar@1
    28
#define xfault xerror
alpar@1
    29
#define dmp_create_poolx(size) dmp_create_pool()
alpar@1
    30
alpar@1
    31
/**********************************************************************/
alpar@1
    32
/* * *              GENERATING AND POSTSOLVING MODEL              * * */
alpar@1
    33
/**********************************************************************/
alpar@1
    34
alpar@1
    35
/*----------------------------------------------------------------------
alpar@1
    36
-- alloc_content - allocate content arrays for all model objects.
alpar@1
    37
--
alpar@1
    38
-- This routine allocates content arrays for all existing model objects
alpar@1
    39
-- and thereby finalizes creating model.
alpar@1
    40
--
alpar@1
    41
-- This routine must be called immediately after reading model section,
alpar@1
    42
-- i.e. before reading data section or generating model. */
alpar@1
    43
alpar@1
    44
void alloc_content(MPL *mpl)
alpar@1
    45
{     STATEMENT *stmt;
alpar@1
    46
      /* walk through all model statements */
alpar@1
    47
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
    48
      {  switch (stmt->type)
alpar@1
    49
         {  case A_SET:
alpar@1
    50
               /* model set */
alpar@1
    51
               xassert(stmt->u.set->array == NULL);
alpar@1
    52
               stmt->u.set->array = create_array(mpl, A_ELEMSET,
alpar@1
    53
                  stmt->u.set->dim);
alpar@1
    54
               break;
alpar@1
    55
            case A_PARAMETER:
alpar@1
    56
               /* model parameter */
alpar@1
    57
               xassert(stmt->u.par->array == NULL);
alpar@1
    58
               switch (stmt->u.par->type)
alpar@1
    59
               {  case A_NUMERIC:
alpar@1
    60
                  case A_INTEGER:
alpar@1
    61
                  case A_BINARY:
alpar@1
    62
                     stmt->u.par->array = create_array(mpl, A_NUMERIC,
alpar@1
    63
                        stmt->u.par->dim);
alpar@1
    64
                     break;
alpar@1
    65
                  case A_SYMBOLIC:
alpar@1
    66
                     stmt->u.par->array = create_array(mpl, A_SYMBOLIC,
alpar@1
    67
                        stmt->u.par->dim);
alpar@1
    68
                     break;
alpar@1
    69
                  default:
alpar@1
    70
                     xassert(stmt != stmt);
alpar@1
    71
               }
alpar@1
    72
               break;
alpar@1
    73
            case A_VARIABLE:
alpar@1
    74
               /* model variable */
alpar@1
    75
               xassert(stmt->u.var->array == NULL);
alpar@1
    76
               stmt->u.var->array = create_array(mpl, A_ELEMVAR,
alpar@1
    77
                  stmt->u.var->dim);
alpar@1
    78
               break;
alpar@1
    79
            case A_CONSTRAINT:
alpar@1
    80
               /* model constraint/objective */
alpar@1
    81
               xassert(stmt->u.con->array == NULL);
alpar@1
    82
               stmt->u.con->array = create_array(mpl, A_ELEMCON,
alpar@1
    83
                  stmt->u.con->dim);
alpar@1
    84
               break;
alpar@1
    85
#if 1 /* 11/II-2008 */
alpar@1
    86
            case A_TABLE:
alpar@1
    87
#endif
alpar@1
    88
            case A_SOLVE:
alpar@1
    89
            case A_CHECK:
alpar@1
    90
            case A_DISPLAY:
alpar@1
    91
            case A_PRINTF:
alpar@1
    92
            case A_FOR:
alpar@1
    93
               /* functional statements have no content array */
alpar@1
    94
               break;
alpar@1
    95
            default:
alpar@1
    96
               xassert(stmt != stmt);
alpar@1
    97
         }
alpar@1
    98
      }
alpar@1
    99
      return;
alpar@1
   100
}
alpar@1
   101
alpar@1
   102
/*----------------------------------------------------------------------
alpar@1
   103
-- generate_model - generate model.
alpar@1
   104
--
alpar@1
   105
-- This routine executes the model statements which precede the solve
alpar@1
   106
-- statement. */
alpar@1
   107
alpar@1
   108
void generate_model(MPL *mpl)
alpar@1
   109
{     STATEMENT *stmt;
alpar@1
   110
      xassert(!mpl->flag_p);
alpar@1
   111
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   112
      {  execute_statement(mpl, stmt);
alpar@1
   113
         if (mpl->stmt->type == A_SOLVE) break;
alpar@1
   114
      }
alpar@1
   115
      mpl->stmt = stmt;
alpar@1
   116
      return;
alpar@1
   117
}
alpar@1
   118
alpar@1
   119
/*----------------------------------------------------------------------
alpar@1
   120
-- build_problem - build problem instance.
alpar@1
   121
--
alpar@1
   122
-- This routine builds lists of rows and columns for problem instance,
alpar@1
   123
-- which corresponds to the generated model. */
alpar@1
   124
alpar@1
   125
void build_problem(MPL *mpl)
alpar@1
   126
{     STATEMENT *stmt;
alpar@1
   127
      MEMBER *memb;
alpar@1
   128
      VARIABLE *v;
alpar@1
   129
      CONSTRAINT *c;
alpar@1
   130
      FORMULA *t;
alpar@1
   131
      int i, j;
alpar@1
   132
      xassert(mpl->m == 0);
alpar@1
   133
      xassert(mpl->n == 0);
alpar@1
   134
      xassert(mpl->row == NULL);
alpar@1
   135
      xassert(mpl->col == NULL);
alpar@1
   136
      /* check that all elemental variables has zero column numbers */
alpar@1
   137
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   138
      {  if (stmt->type == A_VARIABLE)
alpar@1
   139
         {  v = stmt->u.var;
alpar@1
   140
            for (memb = v->array->head; memb != NULL; memb = memb->next)
alpar@1
   141
               xassert(memb->value.var->j == 0);
alpar@1
   142
         }
alpar@1
   143
      }
alpar@1
   144
      /* assign row numbers to elemental constraints and objectives */
alpar@1
   145
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   146
      {  if (stmt->type == A_CONSTRAINT)
alpar@1
   147
         {  c = stmt->u.con;
alpar@1
   148
            for (memb = c->array->head; memb != NULL; memb = memb->next)
alpar@1
   149
            {  xassert(memb->value.con->i == 0);
alpar@1
   150
               memb->value.con->i = ++mpl->m;
alpar@1
   151
               /* walk through linear form and mark elemental variables,
alpar@1
   152
                  which are referenced at least once */
alpar@1
   153
               for (t = memb->value.con->form; t != NULL; t = t->next)
alpar@1
   154
               {  xassert(t->var != NULL);
alpar@1
   155
                  t->var->memb->value.var->j = -1;
alpar@1
   156
               }
alpar@1
   157
            }
alpar@1
   158
         }
alpar@1
   159
      }
alpar@1
   160
      /* assign column numbers to marked elemental variables */
alpar@1
   161
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   162
      {  if (stmt->type == A_VARIABLE)
alpar@1
   163
         {  v = stmt->u.var;
alpar@1
   164
            for (memb = v->array->head; memb != NULL; memb = memb->next)
alpar@1
   165
               if (memb->value.var->j != 0) memb->value.var->j =
alpar@1
   166
                  ++mpl->n;
alpar@1
   167
         }
alpar@1
   168
      }
alpar@1
   169
      /* build list of rows */
alpar@1
   170
      mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *));
alpar@1
   171
      for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL;
alpar@1
   172
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   173
      {  if (stmt->type == A_CONSTRAINT)
alpar@1
   174
         {  c = stmt->u.con;
alpar@1
   175
            for (memb = c->array->head; memb != NULL; memb = memb->next)
alpar@1
   176
            {  i = memb->value.con->i;
alpar@1
   177
               xassert(1 <= i && i <= mpl->m);
alpar@1
   178
               xassert(mpl->row[i] == NULL);
alpar@1
   179
               mpl->row[i] = memb->value.con;
alpar@1
   180
            }
alpar@1
   181
         }
alpar@1
   182
      }
alpar@1
   183
      for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL);
alpar@1
   184
      /* build list of columns */
alpar@1
   185
      mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *));
alpar@1
   186
      for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL;
alpar@1
   187
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   188
      {  if (stmt->type == A_VARIABLE)
alpar@1
   189
         {  v = stmt->u.var;
alpar@1
   190
            for (memb = v->array->head; memb != NULL; memb = memb->next)
alpar@1
   191
            {  j = memb->value.var->j;
alpar@1
   192
               if (j == 0) continue;
alpar@1
   193
               xassert(1 <= j && j <= mpl->n);
alpar@1
   194
               xassert(mpl->col[j] == NULL);
alpar@1
   195
               mpl->col[j] = memb->value.var;
alpar@1
   196
            }
alpar@1
   197
         }
alpar@1
   198
      }
alpar@1
   199
      for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL);
alpar@1
   200
      return;
alpar@1
   201
}
alpar@1
   202
alpar@1
   203
/*----------------------------------------------------------------------
alpar@1
   204
-- postsolve_model - postsolve model.
alpar@1
   205
--
alpar@1
   206
-- This routine executes the model statements which follow the solve
alpar@1
   207
-- statement. */
alpar@1
   208
alpar@1
   209
void postsolve_model(MPL *mpl)
alpar@1
   210
{     STATEMENT *stmt;
alpar@1
   211
      xassert(!mpl->flag_p);
alpar@1
   212
      mpl->flag_p = 1;
alpar@1
   213
      for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next)
alpar@1
   214
         execute_statement(mpl, stmt);
alpar@1
   215
      mpl->stmt = NULL;
alpar@1
   216
      return;
alpar@1
   217
}
alpar@1
   218
alpar@1
   219
/*----------------------------------------------------------------------
alpar@1
   220
-- clean_model - clean model content.
alpar@1
   221
--
alpar@1
   222
-- This routine cleans the model content that assumes deleting all stuff
alpar@1
   223
-- dynamically allocated on generating/postsolving phase.
alpar@1
   224
--
alpar@1
   225
-- Actually cleaning model content is not needed. This function is used
alpar@1
   226
-- mainly to be sure that there were no logical errors on using dynamic
alpar@1
   227
-- memory pools during the generation phase.
alpar@1
   228
--
alpar@1
   229
-- NOTE: This routine must not be called if any errors were detected on
alpar@1
   230
--       the generation phase. */
alpar@1
   231
alpar@1
   232
void clean_model(MPL *mpl)
alpar@1
   233
{     STATEMENT *stmt;
alpar@1
   234
      for (stmt = mpl->model; stmt != NULL; stmt = stmt->next)
alpar@1
   235
         clean_statement(mpl, stmt);
alpar@1
   236
      /* check that all atoms have been returned to their pools */
alpar@1
   237
      if (dmp_in_use(mpl->strings).lo != 0)
alpar@1
   238
         error(mpl, "internal logic error: %d string segment(s) were lo"
alpar@1
   239
            "st", dmp_in_use(mpl->strings).lo);
alpar@1
   240
      if (dmp_in_use(mpl->symbols).lo != 0)
alpar@1
   241
         error(mpl, "internal logic error: %d symbol(s) were lost",
alpar@1
   242
            dmp_in_use(mpl->symbols).lo);
alpar@1
   243
      if (dmp_in_use(mpl->tuples).lo != 0)
alpar@1
   244
         error(mpl, "internal logic error: %d n-tuple component(s) were"
alpar@1
   245
            " lost", dmp_in_use(mpl->tuples).lo);
alpar@1
   246
      if (dmp_in_use(mpl->arrays).lo != 0)
alpar@1
   247
         error(mpl, "internal logic error: %d array(s) were lost",
alpar@1
   248
            dmp_in_use(mpl->arrays).lo);
alpar@1
   249
      if (dmp_in_use(mpl->members).lo != 0)
alpar@1
   250
         error(mpl, "internal logic error: %d array member(s) were lost"
alpar@1
   251
            , dmp_in_use(mpl->members).lo);
alpar@1
   252
      if (dmp_in_use(mpl->elemvars).lo != 0)
alpar@1
   253
         error(mpl, "internal logic error: %d elemental variable(s) wer"
alpar@1
   254
            "e lost", dmp_in_use(mpl->elemvars).lo);
alpar@1
   255
      if (dmp_in_use(mpl->formulae).lo != 0)
alpar@1
   256
         error(mpl, "internal logic error: %d linear term(s) were lost",
alpar@1
   257
            dmp_in_use(mpl->formulae).lo);
alpar@1
   258
      if (dmp_in_use(mpl->elemcons).lo != 0)
alpar@1
   259
         error(mpl, "internal logic error: %d elemental constraint(s) w"
alpar@1
   260
            "ere lost", dmp_in_use(mpl->elemcons).lo);
alpar@1
   261
      return;
alpar@1
   262
}
alpar@1
   263
alpar@1
   264
/**********************************************************************/
alpar@1
   265
/* * *                        INPUT/OUTPUT                        * * */
alpar@1
   266
/**********************************************************************/
alpar@1
   267
alpar@1
   268
/*----------------------------------------------------------------------
alpar@1
   269
-- open_input - open input text file.
alpar@1
   270
--
alpar@1
   271
-- This routine opens the input text file for scanning. */
alpar@1
   272
alpar@1
   273
void open_input(MPL *mpl, char *file)
alpar@1
   274
{     mpl->line = 0;
alpar@1
   275
      mpl->c = '\n';
alpar@1
   276
      mpl->token = 0;
alpar@1
   277
      mpl->imlen = 0;
alpar@1
   278
      mpl->image[0] = '\0';
alpar@1
   279
      mpl->value = 0.0;
alpar@1
   280
      mpl->b_token = T_EOF;
alpar@1
   281
      mpl->b_imlen = 0;
alpar@1
   282
      mpl->b_image[0] = '\0';
alpar@1
   283
      mpl->b_value = 0.0;
alpar@1
   284
      mpl->f_dots = 0;
alpar@1
   285
      mpl->f_scan = 0;
alpar@1
   286
      mpl->f_token = 0;
alpar@1
   287
      mpl->f_imlen = 0;
alpar@1
   288
      mpl->f_image[0] = '\0';
alpar@1
   289
      mpl->f_value = 0.0;
alpar@1
   290
      memset(mpl->context, ' ', CONTEXT_SIZE);
alpar@1
   291
      mpl->c_ptr = 0;
alpar@1
   292
      xassert(mpl->in_fp == NULL);
alpar@1
   293
      mpl->in_fp = xfopen(file, "r");
alpar@1
   294
      if (mpl->in_fp == NULL)
alpar@1
   295
         error(mpl, "unable to open %s - %s", file, xerrmsg());
alpar@1
   296
      mpl->in_file = file;
alpar@1
   297
      /* scan the very first character */
alpar@1
   298
      get_char(mpl);
alpar@1
   299
      /* scan the very first token */
alpar@1
   300
      get_token(mpl);
alpar@1
   301
      return;
alpar@1
   302
}
alpar@1
   303
alpar@1
   304
/*----------------------------------------------------------------------
alpar@1
   305
-- read_char - read next character from input text file.
alpar@1
   306
--
alpar@1
   307
-- This routine returns a next ASCII character read from the input text
alpar@1
   308
-- file. If the end of file has been reached, EOF is returned. */
alpar@1
   309
alpar@1
   310
int read_char(MPL *mpl)
alpar@1
   311
{     int c;
alpar@1
   312
      xassert(mpl->in_fp != NULL);
alpar@1
   313
      c = xfgetc(mpl->in_fp);
alpar@1
   314
      if (c < 0)
alpar@1
   315
      {  if (xferror(mpl->in_fp))
alpar@1
   316
            error(mpl, "read error on %s - %s", mpl->in_file,
alpar@1
   317
               xerrmsg());
alpar@1
   318
         c = EOF;
alpar@1
   319
      }
alpar@1
   320
      return c;
alpar@1
   321
}
alpar@1
   322
alpar@1
   323
/*----------------------------------------------------------------------
alpar@1
   324
-- close_input - close input text file.
alpar@1
   325
--
alpar@1
   326
-- This routine closes the input text file. */
alpar@1
   327
alpar@1
   328
void close_input(MPL *mpl)
alpar@1
   329
{     xassert(mpl->in_fp != NULL);
alpar@1
   330
      xfclose(mpl->in_fp);
alpar@1
   331
      mpl->in_fp = NULL;
alpar@1
   332
      mpl->in_file = NULL;
alpar@1
   333
      return;
alpar@1
   334
}
alpar@1
   335
alpar@1
   336
/*----------------------------------------------------------------------
alpar@1
   337
-- open_output - open output text file.
alpar@1
   338
--
alpar@1
   339
-- This routine opens the output text file for writing data produced by
alpar@1
   340
-- display and printf statements. */
alpar@1
   341
alpar@1
   342
void open_output(MPL *mpl, char *file)
alpar@1
   343
{     xassert(mpl->out_fp == NULL);
alpar@1
   344
      if (file == NULL)
alpar@1
   345
      {  file = "<stdout>";
alpar@1
   346
         mpl->out_fp = (void *)stdout;
alpar@1
   347
      }
alpar@1
   348
      else
alpar@1
   349
      {  mpl->out_fp = xfopen(file, "w");
alpar@1
   350
         if (mpl->out_fp == NULL)
alpar@1
   351
            error(mpl, "unable to create %s - %s", file, xerrmsg());
alpar@1
   352
      }
alpar@1
   353
      mpl->out_file = xmalloc(strlen(file)+1);
alpar@1
   354
      strcpy(mpl->out_file, file);
alpar@1
   355
      return;
alpar@1
   356
}
alpar@1
   357
alpar@1
   358
/*----------------------------------------------------------------------
alpar@1
   359
-- write_char - write next character to output text file.
alpar@1
   360
--
alpar@1
   361
-- This routine writes an ASCII character to the output text file. */
alpar@1
   362
alpar@1
   363
void write_char(MPL *mpl, int c)
alpar@1
   364
{     xassert(mpl->out_fp != NULL);
alpar@1
   365
      if (mpl->out_fp == (void *)stdout)
alpar@1
   366
         xprintf("%c", c);
alpar@1
   367
      else
alpar@1
   368
         xfprintf(mpl->out_fp, "%c", c);
alpar@1
   369
      return;
alpar@1
   370
}
alpar@1
   371
alpar@1
   372
/*----------------------------------------------------------------------
alpar@1
   373
-- write_text - format and write text to output text file.
alpar@1
   374
--
alpar@1
   375
-- This routine formats a text using the format control string and then
alpar@1
   376
-- writes this text to the output text file. */
alpar@1
   377
alpar@1
   378
void write_text(MPL *mpl, char *fmt, ...)
alpar@1
   379
{     va_list arg;
alpar@1
   380
      char buf[OUTBUF_SIZE], *c;
alpar@1
   381
      va_start(arg, fmt);
alpar@1
   382
      vsprintf(buf, fmt, arg);
alpar@1
   383
      xassert(strlen(buf) < sizeof(buf));
alpar@1
   384
      va_end(arg);
alpar@1
   385
      for (c = buf; *c != '\0'; c++) write_char(mpl, *c);
alpar@1
   386
      return;
alpar@1
   387
}
alpar@1
   388
alpar@1
   389
/*----------------------------------------------------------------------
alpar@1
   390
-- flush_output - finalize writing data to output text file.
alpar@1
   391
--
alpar@1
   392
-- This routine finalizes writing data to the output text file. */
alpar@1
   393
alpar@1
   394
void flush_output(MPL *mpl)
alpar@1
   395
{     xassert(mpl->out_fp != NULL);
alpar@1
   396
      if (mpl->out_fp != (void *)stdout)
alpar@1
   397
      {  xfflush(mpl->out_fp);
alpar@1
   398
         if (xferror(mpl->out_fp))
alpar@1
   399
            error(mpl, "write error on %s - %s", mpl->out_file,
alpar@1
   400
               xerrmsg());
alpar@1
   401
      }
alpar@1
   402
      return;
alpar@1
   403
}
alpar@1
   404
alpar@1
   405
/**********************************************************************/
alpar@1
   406
/* * *                      SOLVER INTERFACE                      * * */
alpar@1
   407
/**********************************************************************/
alpar@1
   408
alpar@1
   409
/*----------------------------------------------------------------------
alpar@1
   410
-- error - print error message and terminate model processing.
alpar@1
   411
--
alpar@1
   412
-- This routine formats and prints an error message and then terminates
alpar@1
   413
-- model processing. */
alpar@1
   414
alpar@1
   415
void error(MPL *mpl, char *fmt, ...)
alpar@1
   416
{     va_list arg;
alpar@1
   417
      char msg[4095+1];
alpar@1
   418
      va_start(arg, fmt);
alpar@1
   419
      vsprintf(msg, fmt, arg);
alpar@1
   420
      xassert(strlen(msg) < sizeof(msg));
alpar@1
   421
      va_end(arg);
alpar@1
   422
      switch (mpl->phase)
alpar@1
   423
      {  case 1:
alpar@1
   424
         case 2:
alpar@1
   425
            /* translation phase */
alpar@1
   426
            xprintf("%s:%d: %s\n",
alpar@1
   427
               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
alpar@1
   428
               mpl->line, msg);
alpar@1
   429
            print_context(mpl);
alpar@1
   430
            break;
alpar@1
   431
         case 3:
alpar@1
   432
            /* generation/postsolve phase */
alpar@1
   433
            xprintf("%s:%d: %s\n",
alpar@1
   434
               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
alpar@1
   435
               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
alpar@1
   436
            break;
alpar@1
   437
         default:
alpar@1
   438
            xassert(mpl != mpl);
alpar@1
   439
      }
alpar@1
   440
      mpl->phase = 4;
alpar@1
   441
      longjmp(mpl->jump, 1);
alpar@1
   442
      /* no return */
alpar@1
   443
}
alpar@1
   444
alpar@1
   445
/*----------------------------------------------------------------------
alpar@1
   446
-- warning - print warning message and continue model processing.
alpar@1
   447
--
alpar@1
   448
-- This routine formats and prints a warning message and returns to the
alpar@1
   449
-- calling program. */
alpar@1
   450
alpar@1
   451
void warning(MPL *mpl, char *fmt, ...)
alpar@1
   452
{     va_list arg;
alpar@1
   453
      char msg[4095+1];
alpar@1
   454
      va_start(arg, fmt);
alpar@1
   455
      vsprintf(msg, fmt, arg);
alpar@1
   456
      xassert(strlen(msg) < sizeof(msg));
alpar@1
   457
      va_end(arg);
alpar@1
   458
      switch (mpl->phase)
alpar@1
   459
      {  case 1:
alpar@1
   460
         case 2:
alpar@1
   461
            /* translation phase */
alpar@1
   462
            xprintf("%s:%d: warning: %s\n",
alpar@1
   463
               mpl->in_file == NULL ? "(unknown)" : mpl->in_file,
alpar@1
   464
               mpl->line, msg);
alpar@1
   465
            break;
alpar@1
   466
         case 3:
alpar@1
   467
            /* generation/postsolve phase */
alpar@1
   468
            xprintf("%s:%d: warning: %s\n",
alpar@1
   469
               mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file,
alpar@1
   470
               mpl->stmt == NULL ? 0 : mpl->stmt->line, msg);
alpar@1
   471
            break;
alpar@1
   472
         default:
alpar@1
   473
            xassert(mpl != mpl);
alpar@1
   474
      }
alpar@1
   475
      return;
alpar@1
   476
}
alpar@1
   477
alpar@1
   478
/*----------------------------------------------------------------------
alpar@1
   479
-- mpl_initialize - create and initialize translator database.
alpar@1
   480
--
alpar@1
   481
-- *Synopsis*
alpar@1
   482
--
alpar@1
   483
-- #include "glpmpl.h"
alpar@1
   484
-- MPL *mpl_initialize(void);
alpar@1
   485
--
alpar@1
   486
-- *Description*
alpar@1
   487
--
alpar@1
   488
-- The routine mpl_initialize creates and initializes the database used
alpar@1
   489
-- by the GNU MathProg translator.
alpar@1
   490
--
alpar@1
   491
-- *Returns*
alpar@1
   492
--
alpar@1
   493
-- The routine returns a pointer to the database created. */
alpar@1
   494
alpar@1
   495
MPL *mpl_initialize(void)
alpar@1
   496
{     MPL *mpl;
alpar@1
   497
      mpl = xmalloc(sizeof(MPL));
alpar@1
   498
      /* scanning segment */
alpar@1
   499
      mpl->line = 0;
alpar@1
   500
      mpl->c = 0;
alpar@1
   501
      mpl->token = 0;
alpar@1
   502
      mpl->imlen = 0;
alpar@1
   503
      mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char));
alpar@1
   504
      mpl->image[0] = '\0';
alpar@1
   505
      mpl->value = 0.0;
alpar@1
   506
      mpl->b_token = 0;
alpar@1
   507
      mpl->b_imlen = 0;
alpar@1
   508
      mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char));
alpar@1
   509
      mpl->b_image[0] = '\0';
alpar@1
   510
      mpl->b_value = 0.0;
alpar@1
   511
      mpl->f_dots = 0;
alpar@1
   512
      mpl->f_scan = 0;
alpar@1
   513
      mpl->f_token = 0;
alpar@1
   514
      mpl->f_imlen = 0;
alpar@1
   515
      mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char));
alpar@1
   516
      mpl->f_image[0] = '\0';
alpar@1
   517
      mpl->f_value = 0.0;
alpar@1
   518
      mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char));
alpar@1
   519
      memset(mpl->context, ' ', CONTEXT_SIZE);
alpar@1
   520
      mpl->c_ptr = 0;
alpar@1
   521
      mpl->flag_d = 0;
alpar@1
   522
      /* translating segment */
alpar@1
   523
      mpl->pool = dmp_create_poolx(0);
alpar@1
   524
      mpl->tree = avl_create_tree(avl_strcmp, NULL);
alpar@1
   525
      mpl->model = NULL;
alpar@1
   526
      mpl->flag_x = 0;
alpar@1
   527
      mpl->as_within = 0;
alpar@1
   528
      mpl->as_in = 0;
alpar@1
   529
      mpl->as_binary = 0;
alpar@1
   530
      mpl->flag_s = 0;
alpar@1
   531
      /* common segment */
alpar@1
   532
      mpl->strings = dmp_create_poolx(sizeof(STRING));
alpar@1
   533
      mpl->symbols = dmp_create_poolx(sizeof(SYMBOL));
alpar@1
   534
      mpl->tuples = dmp_create_poolx(sizeof(TUPLE));
alpar@1
   535
      mpl->arrays = dmp_create_poolx(sizeof(ARRAY));
alpar@1
   536
      mpl->members = dmp_create_poolx(sizeof(MEMBER));
alpar@1
   537
      mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR));
alpar@1
   538
      mpl->formulae = dmp_create_poolx(sizeof(FORMULA));
alpar@1
   539
      mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON));
alpar@1
   540
      mpl->a_list = NULL;
alpar@1
   541
      mpl->sym_buf = xcalloc(255+1, sizeof(char));
alpar@1
   542
      mpl->sym_buf[0] = '\0';
alpar@1
   543
      mpl->tup_buf = xcalloc(255+1, sizeof(char));
alpar@1
   544
      mpl->tup_buf[0] = '\0';
alpar@1
   545
      /* generating/postsolving segment */
alpar@1
   546
      mpl->rand = rng_create_rand();
alpar@1
   547
      mpl->flag_p = 0;
alpar@1
   548
      mpl->stmt = NULL;
alpar@1
   549
#if 1 /* 11/II-2008 */
alpar@1
   550
      mpl->dca = NULL;
alpar@1
   551
#endif
alpar@1
   552
      mpl->m = 0;
alpar@1
   553
      mpl->n = 0;
alpar@1
   554
      mpl->row = NULL;
alpar@1
   555
      mpl->col = NULL;
alpar@1
   556
      /* input/output segment */
alpar@1
   557
      mpl->in_fp = NULL;
alpar@1
   558
      mpl->in_file = NULL;
alpar@1
   559
      mpl->out_fp = NULL;
alpar@1
   560
      mpl->out_file = NULL;
alpar@1
   561
      mpl->prt_fp = NULL;
alpar@1
   562
      mpl->prt_file = NULL;
alpar@1
   563
      /* solver interface segment */
alpar@1
   564
      if (setjmp(mpl->jump)) xassert(mpl != mpl);
alpar@1
   565
      mpl->phase = 0;
alpar@1
   566
      mpl->mod_file = NULL;
alpar@1
   567
      mpl->mpl_buf = xcalloc(255+1, sizeof(char));
alpar@1
   568
      mpl->mpl_buf[0] = '\0';
alpar@1
   569
      return mpl;
alpar@1
   570
}
alpar@1
   571
alpar@1
   572
/*----------------------------------------------------------------------
alpar@1
   573
-- mpl_read_model - read model section and optional data section.
alpar@1
   574
--
alpar@1
   575
-- *Synopsis*
alpar@1
   576
--
alpar@1
   577
-- #include "glpmpl.h"
alpar@1
   578
-- int mpl_read_model(MPL *mpl, char *file, int skip_data);
alpar@1
   579
--
alpar@1
   580
-- *Description*
alpar@1
   581
--
alpar@1
   582
-- The routine mpl_read_model reads model section and optionally data
alpar@1
   583
-- section, which may follow the model section, from the text file,
alpar@1
   584
-- whose name is the character string file, performs translating model
alpar@1
   585
-- statements and data blocks, and stores all the information in the
alpar@1
   586
-- translator database.
alpar@1
   587
--
alpar@1
   588
-- The parameter skip_data is a flag. If the input file contains the
alpar@1
   589
-- data section and this flag is set, the data section is not read as
alpar@1
   590
-- if there were no data section and a warning message is issued. This
alpar@1
   591
-- allows reading the data section from another input file.
alpar@1
   592
--
alpar@1
   593
-- This routine should be called once after the routine mpl_initialize
alpar@1
   594
-- and before other API routines.
alpar@1
   595
--
alpar@1
   596
-- *Returns*
alpar@1
   597
--
alpar@1
   598
-- The routine mpl_read_model returns one the following codes:
alpar@1
   599
--
alpar@1
   600
-- 1 - translation successful. The input text file contains only model
alpar@1
   601
--     section. In this case the calling program may call the routine
alpar@1
   602
--     mpl_read_data to read data section from another file.
alpar@1
   603
-- 2 - translation successful. The input text file contains both model
alpar@1
   604
--     and data section.
alpar@1
   605
-- 4 - processing failed due to some errors. In this case the calling
alpar@1
   606
--     program should call the routine mpl_terminate to terminate model
alpar@1
   607
--     processing. */
alpar@1
   608
alpar@1
   609
int mpl_read_model(MPL *mpl, char *file, int skip_data)
alpar@1
   610
{     if (mpl->phase != 0)
alpar@1
   611
         xfault("mpl_read_model: invalid call sequence\n");
alpar@1
   612
      if (file == NULL)
alpar@1
   613
         xfault("mpl_read_model: no input filename specified\n");
alpar@1
   614
      /* set up error handler */
alpar@1
   615
      if (setjmp(mpl->jump)) goto done;
alpar@1
   616
      /* translate model section */
alpar@1
   617
      mpl->phase = 1;
alpar@1
   618
      xprintf("Reading model section from %s...\n", file);
alpar@1
   619
      open_input(mpl, file);
alpar@1
   620
      model_section(mpl);
alpar@1
   621
      if (mpl->model == NULL)
alpar@1
   622
         error(mpl, "empty model section not allowed");
alpar@1
   623
      /* save name of the input text file containing model section for
alpar@1
   624
         error diagnostics during the generation phase */
alpar@1
   625
      mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char));
alpar@1
   626
      strcpy(mpl->mod_file, mpl->in_file);
alpar@1
   627
      /* allocate content arrays for all model objects */
alpar@1
   628
      alloc_content(mpl);
alpar@1
   629
      /* optional data section may begin with the keyword 'data' */
alpar@1
   630
      if (is_keyword(mpl, "data"))
alpar@1
   631
      {  if (skip_data)
alpar@1
   632
         {  warning(mpl, "data section ignored");
alpar@1
   633
            goto skip;
alpar@1
   634
         }
alpar@1
   635
         mpl->flag_d = 1;
alpar@1
   636
         get_token(mpl /* data */);
alpar@1
   637
         if (mpl->token != T_SEMICOLON)
alpar@1
   638
            error(mpl, "semicolon missing where expected");
alpar@1
   639
         get_token(mpl /* ; */);
alpar@1
   640
         /* translate data section */
alpar@1
   641
         mpl->phase = 2;
alpar@1
   642
         xprintf("Reading data section from %s...\n", file);
alpar@1
   643
         data_section(mpl);
alpar@1
   644
      }
alpar@1
   645
      /* process end statement */
alpar@1
   646
      end_statement(mpl);
alpar@1
   647
skip: xprintf("%d line%s were read\n",
alpar@1
   648
         mpl->line, mpl->line == 1 ? "" : "s");
alpar@1
   649
      close_input(mpl);
alpar@1
   650
done: /* return to the calling program */
alpar@1
   651
      return mpl->phase;
alpar@1
   652
}
alpar@1
   653
alpar@1
   654
/*----------------------------------------------------------------------
alpar@1
   655
-- mpl_read_data - read data section.
alpar@1
   656
--
alpar@1
   657
-- *Synopsis*
alpar@1
   658
--
alpar@1
   659
-- #include "glpmpl.h"
alpar@1
   660
-- int mpl_read_data(MPL *mpl, char *file);
alpar@1
   661
--
alpar@1
   662
-- *Description*
alpar@1
   663
--
alpar@1
   664
-- The routine mpl_read_data reads data section from the text file,
alpar@1
   665
-- whose name is the character string file, performs translating data
alpar@1
   666
-- blocks, and stores the data read in the translator database.
alpar@1
   667
--
alpar@1
   668
-- If this routine is used, it should be called once after the routine
alpar@1
   669
-- mpl_read_model and if the latter returned the code 1.
alpar@1
   670
--
alpar@1
   671
-- *Returns*
alpar@1
   672
--
alpar@1
   673
-- The routine mpl_read_data returns one of the following codes:
alpar@1
   674
--
alpar@1
   675
-- 2 - data section has been successfully processed.
alpar@1
   676
-- 4 - processing failed due to some errors. In this case the calling
alpar@1
   677
--     program should call the routine mpl_terminate to terminate model
alpar@1
   678
--     processing. */
alpar@1
   679
alpar@1
   680
int mpl_read_data(MPL *mpl, char *file)
alpar@1
   681
#if 0 /* 02/X-2008 */
alpar@1
   682
{     if (mpl->phase != 1)
alpar@1
   683
#else
alpar@1
   684
{     if (!(mpl->phase == 1 || mpl->phase == 2))
alpar@1
   685
#endif
alpar@1
   686
         xfault("mpl_read_data: invalid call sequence\n");
alpar@1
   687
      if (file == NULL)
alpar@1
   688
         xfault("mpl_read_data: no input filename specified\n");
alpar@1
   689
      /* set up error handler */
alpar@1
   690
      if (setjmp(mpl->jump)) goto done;
alpar@1
   691
      /* process data section */
alpar@1
   692
      mpl->phase = 2;
alpar@1
   693
      xprintf("Reading data section from %s...\n", file);
alpar@1
   694
      mpl->flag_d = 1;
alpar@1
   695
      open_input(mpl, file);
alpar@1
   696
      /* in this case the keyword 'data' is optional */
alpar@1
   697
      if (is_literal(mpl, "data"))
alpar@1
   698
      {  get_token(mpl /* data */);
alpar@1
   699
         if (mpl->token != T_SEMICOLON)
alpar@1
   700
            error(mpl, "semicolon missing where expected");
alpar@1
   701
         get_token(mpl /* ; */);
alpar@1
   702
      }
alpar@1
   703
      data_section(mpl);
alpar@1
   704
      /* process end statement */
alpar@1
   705
      end_statement(mpl);
alpar@1
   706
      xprintf("%d line%s were read\n",
alpar@1
   707
         mpl->line, mpl->line == 1 ? "" : "s");
alpar@1
   708
      close_input(mpl);
alpar@1
   709
done: /* return to the calling program */
alpar@1
   710
      return mpl->phase;
alpar@1
   711
}
alpar@1
   712
alpar@1
   713
/*----------------------------------------------------------------------
alpar@1
   714
-- mpl_generate - generate model.
alpar@1
   715
--
alpar@1
   716
-- *Synopsis*
alpar@1
   717
--
alpar@1
   718
-- #include "glpmpl.h"
alpar@1
   719
-- int mpl_generate(MPL *mpl, char *file);
alpar@1
   720
--
alpar@1
   721
-- *Description*
alpar@1
   722
--
alpar@1
   723
-- The routine mpl_generate generates the model using its description
alpar@1
   724
-- stored in the translator database. This phase means generating all
alpar@1
   725
-- variables, constraints, and objectives, executing check and display
alpar@1
   726
-- statements, which precede the solve statement (if it is presented),
alpar@1
   727
-- and building the problem instance.
alpar@1
   728
--
alpar@1
   729
-- The character string file specifies the name of output text file, to
alpar@1
   730
-- which output produced by display statements should be written. It is
alpar@1
   731
-- allowed to specify NULL, in which case the output goes to stdout via
alpar@1
   732
-- the routine print.
alpar@1
   733
--
alpar@1
   734
-- This routine should be called once after the routine mpl_read_model
alpar@1
   735
-- or mpl_read_data and if one of the latters returned the code 2.
alpar@1
   736
--
alpar@1
   737
-- *Returns*
alpar@1
   738
--
alpar@1
   739
-- The routine mpl_generate returns one of the following codes:
alpar@1
   740
--
alpar@1
   741
-- 3 - model has been successfully generated. In this case the calling
alpar@1
   742
--     program may call other api routines to obtain components of the
alpar@1
   743
--     problem instance from the translator database.
alpar@1
   744
-- 4 - processing failed due to some errors. In this case the calling
alpar@1
   745
--     program should call the routine mpl_terminate to terminate model
alpar@1
   746
--     processing. */
alpar@1
   747
alpar@1
   748
int mpl_generate(MPL *mpl, char *file)
alpar@1
   749
{     if (!(mpl->phase == 1 || mpl->phase == 2))
alpar@1
   750
         xfault("mpl_generate: invalid call sequence\n");
alpar@1
   751
      /* set up error handler */
alpar@1
   752
      if (setjmp(mpl->jump)) goto done;
alpar@1
   753
      /* generate model */
alpar@1
   754
      mpl->phase = 3;
alpar@1
   755
      open_output(mpl, file);
alpar@1
   756
      generate_model(mpl);
alpar@1
   757
      flush_output(mpl);
alpar@1
   758
      /* build problem instance */
alpar@1
   759
      build_problem(mpl);
alpar@1
   760
      /* generation phase has been finished */
alpar@1
   761
      xprintf("Model has been successfully generated\n");
alpar@1
   762
done: /* return to the calling program */
alpar@1
   763
      return mpl->phase;
alpar@1
   764
}
alpar@1
   765
alpar@1
   766
/*----------------------------------------------------------------------
alpar@1
   767
-- mpl_get_prob_name - obtain problem (model) name.
alpar@1
   768
--
alpar@1
   769
-- *Synopsis*
alpar@1
   770
--
alpar@1
   771
-- #include "glpmpl.h"
alpar@1
   772
-- char *mpl_get_prob_name(MPL *mpl);
alpar@1
   773
--
alpar@1
   774
-- *Returns*
alpar@1
   775
--
alpar@1
   776
-- The routine mpl_get_prob_name returns a pointer to internal buffer,
alpar@1
   777
-- which contains symbolic name of the problem (model).
alpar@1
   778
--
alpar@1
   779
-- *Note*
alpar@1
   780
--
alpar@1
   781
-- Currently MathProg has no feature to assign a symbolic name to the
alpar@1
   782
-- model. Therefore the routine mpl_get_prob_name tries to construct
alpar@1
   783
-- such name using the name of input text file containing model section,
alpar@1
   784
-- although this is not a good idea (due to portability problems). */
alpar@1
   785
alpar@1
   786
char *mpl_get_prob_name(MPL *mpl)
alpar@1
   787
{     char *name = mpl->mpl_buf;
alpar@1
   788
      char *file = mpl->mod_file;
alpar@1
   789
      int k;
alpar@1
   790
      if (mpl->phase != 3)
alpar@1
   791
         xfault("mpl_get_prob_name: invalid call sequence\n");
alpar@1
   792
      for (;;)
alpar@1
   793
      {  if (strchr(file, '/') != NULL)
alpar@1
   794
            file = strchr(file, '/') + 1;
alpar@1
   795
         else if (strchr(file, '\\') != NULL)
alpar@1
   796
            file = strchr(file, '\\') + 1;
alpar@1
   797
         else if (strchr(file, ':') != NULL)
alpar@1
   798
            file = strchr(file, ':') + 1;
alpar@1
   799
         else
alpar@1
   800
            break;
alpar@1
   801
      }
alpar@1
   802
      for (k = 0; ; k++)
alpar@1
   803
      {  if (k == 255) break;
alpar@1
   804
         if (!(isalnum((unsigned char)*file) || *file == '_')) break;
alpar@1
   805
         name[k] = *file++;
alpar@1
   806
      }
alpar@1
   807
      if (k == 0)
alpar@1
   808
         strcpy(name, "Unknown");
alpar@1
   809
      else
alpar@1
   810
         name[k] = '\0';
alpar@1
   811
      xassert(strlen(name) <= 255);
alpar@1
   812
      return name;
alpar@1
   813
}
alpar@1
   814
alpar@1
   815
/*----------------------------------------------------------------------
alpar@1
   816
-- mpl_get_num_rows - determine number of rows.
alpar@1
   817
--
alpar@1
   818
-- *Synopsis*
alpar@1
   819
--
alpar@1
   820
-- #include "glpmpl.h"
alpar@1
   821
-- int mpl_get_num_rows(MPL *mpl);
alpar@1
   822
--
alpar@1
   823
-- *Returns*
alpar@1
   824
--
alpar@1
   825
-- The routine mpl_get_num_rows returns total number of rows in the
alpar@1
   826
-- problem, where each row is an individual constraint or objective. */
alpar@1
   827
alpar@1
   828
int mpl_get_num_rows(MPL *mpl)
alpar@1
   829
{     if (mpl->phase != 3)
alpar@1
   830
         xfault("mpl_get_num_rows: invalid call sequence\n");
alpar@1
   831
      return mpl->m;
alpar@1
   832
}
alpar@1
   833
alpar@1
   834
/*----------------------------------------------------------------------
alpar@1
   835
-- mpl_get_num_cols - determine number of columns.
alpar@1
   836
--
alpar@1
   837
-- *Synopsis*
alpar@1
   838
--
alpar@1
   839
-- #include "glpmpl.h"
alpar@1
   840
-- int mpl_get_num_cols(MPL *mpl);
alpar@1
   841
--
alpar@1
   842
-- *Returns*
alpar@1
   843
--
alpar@1
   844
-- The routine mpl_get_num_cols returns total number of columns in the
alpar@1
   845
-- problem, where each column is an individual variable. */
alpar@1
   846
alpar@1
   847
int mpl_get_num_cols(MPL *mpl)
alpar@1
   848
{     if (mpl->phase != 3)
alpar@1
   849
         xfault("mpl_get_num_cols: invalid call sequence\n");
alpar@1
   850
      return mpl->n;
alpar@1
   851
}
alpar@1
   852
alpar@1
   853
/*----------------------------------------------------------------------
alpar@1
   854
-- mpl_get_row_name - obtain row name.
alpar@1
   855
--
alpar@1
   856
-- *Synopsis*
alpar@1
   857
--
alpar@1
   858
-- #include "glpmpl.h"
alpar@1
   859
-- char *mpl_get_row_name(MPL *mpl, int i);
alpar@1
   860
--
alpar@1
   861
-- *Returns*
alpar@1
   862
--
alpar@1
   863
-- The routine mpl_get_row_name returns a pointer to internal buffer,
alpar@1
   864
-- which contains symbolic name of i-th row of the problem. */
alpar@1
   865
alpar@1
   866
char *mpl_get_row_name(MPL *mpl, int i)
alpar@1
   867
{     char *name = mpl->mpl_buf, *t;
alpar@1
   868
      int len;
alpar@1
   869
      if (mpl->phase != 3)
alpar@1
   870
         xfault("mpl_get_row_name: invalid call sequence\n");
alpar@1
   871
      if (!(1 <= i && i <= mpl->m))
alpar@1
   872
         xfault("mpl_get_row_name: i = %d; row number out of range\n",
alpar@1
   873
            i);
alpar@1
   874
      strcpy(name, mpl->row[i]->con->name);
alpar@1
   875
      len = strlen(name);
alpar@1
   876
      xassert(len <= 255);
alpar@1
   877
      t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple);
alpar@1
   878
      while (*t)
alpar@1
   879
      {  if (len == 255) break;
alpar@1
   880
         name[len++] = *t++;
alpar@1
   881
      }
alpar@1
   882
      name[len] = '\0';
alpar@1
   883
      if (len == 255) strcpy(name+252, "...");
alpar@1
   884
      xassert(strlen(name) <= 255);
alpar@1
   885
      return name;
alpar@1
   886
}
alpar@1
   887
alpar@1
   888
/*----------------------------------------------------------------------
alpar@1
   889
-- mpl_get_row_kind - determine row kind.
alpar@1
   890
--
alpar@1
   891
-- *Synopsis*
alpar@1
   892
--
alpar@1
   893
-- #include "glpmpl.h"
alpar@1
   894
-- int mpl_get_row_kind(MPL *mpl, int i);
alpar@1
   895
--
alpar@1
   896
-- *Returns*
alpar@1
   897
--
alpar@1
   898
-- The routine mpl_get_row_kind returns the kind of i-th row, which can
alpar@1
   899
-- be one of the following:
alpar@1
   900
--
alpar@1
   901
-- MPL_ST  - non-free (constraint) row;
alpar@1
   902
-- MPL_MIN - free (objective) row to be minimized;
alpar@1
   903
-- MPL_MAX - free (objective) row to be maximized. */
alpar@1
   904
alpar@1
   905
int mpl_get_row_kind(MPL *mpl, int i)
alpar@1
   906
{     int kind;
alpar@1
   907
      if (mpl->phase != 3)
alpar@1
   908
         xfault("mpl_get_row_kind: invalid call sequence\n");
alpar@1
   909
      if (!(1 <= i && i <= mpl->m))
alpar@1
   910
         xfault("mpl_get_row_kind: i = %d; row number out of range\n",
alpar@1
   911
            i);
alpar@1
   912
      switch (mpl->row[i]->con->type)
alpar@1
   913
      {  case A_CONSTRAINT:
alpar@1
   914
            kind = MPL_ST; break;
alpar@1
   915
         case A_MINIMIZE:
alpar@1
   916
            kind = MPL_MIN; break;
alpar@1
   917
         case A_MAXIMIZE:
alpar@1
   918
            kind = MPL_MAX; break;
alpar@1
   919
         default:
alpar@1
   920
            xassert(mpl != mpl);
alpar@1
   921
      }
alpar@1
   922
      return kind;
alpar@1
   923
}
alpar@1
   924
alpar@1
   925
/*----------------------------------------------------------------------
alpar@1
   926
-- mpl_get_row_bnds - obtain row bounds.
alpar@1
   927
--
alpar@1
   928
-- *Synopsis*
alpar@1
   929
--
alpar@1
   930
-- #include "glpmpl.h"
alpar@1
   931
-- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub);
alpar@1
   932
--
alpar@1
   933
-- *Description*
alpar@1
   934
--
alpar@1
   935
-- The routine mpl_get_row_bnds stores lower and upper bounds of i-th
alpar@1
   936
-- row of the problem to the locations, which the parameters lb and ub
alpar@1
   937
-- point to, respectively. Besides the routine returns the type of the
alpar@1
   938
-- i-th row.
alpar@1
   939
--
alpar@1
   940
-- If some of the parameters lb and ub is NULL, the corresponding bound
alpar@1
   941
-- value is not stored.
alpar@1
   942
--
alpar@1
   943
-- Types and bounds have the following meaning:
alpar@1
   944
--
alpar@1
   945
--     Type           Bounds          Note
alpar@1
   946
--    -----------------------------------------------------------
alpar@1
   947
--    MPL_FR   -inf <  f(x) <  +inf   Free linear form
alpar@1
   948
--    MPL_LO     lb <= f(x) <  +inf   Inequality f(x) >= lb
alpar@1
   949
--    MPL_UP   -inf <  f(x) <=  ub    Inequality f(x) <= ub
alpar@1
   950
--    MPL_DB     lb <= f(x) <=  ub    Inequality lb <= f(x) <= ub
alpar@1
   951
--    MPL_FX           f(x)  =  lb    Equality f(x) = lb
alpar@1
   952
--
alpar@1
   953
-- where f(x) is the corresponding linear form of the i-th row.
alpar@1
   954
--
alpar@1
   955
-- If the row has no lower bound, *lb is set to zero; if the row has
alpar@1
   956
-- no upper bound, *ub is set to zero; and if the row is of fixed type,
alpar@1
   957
-- both *lb and *ub are set to the same value.
alpar@1
   958
--
alpar@1
   959
-- *Returns*
alpar@1
   960
--
alpar@1
   961
-- The routine returns the type of the i-th row as it is stated in the
alpar@1
   962
-- table above. */
alpar@1
   963
alpar@1
   964
int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub)
alpar@1
   965
{     ELEMCON *con;
alpar@1
   966
      int type;
alpar@1
   967
      double lb, ub;
alpar@1
   968
      if (mpl->phase != 3)
alpar@1
   969
         xfault("mpl_get_row_bnds: invalid call sequence\n");
alpar@1
   970
      if (!(1 <= i && i <= mpl->m))
alpar@1
   971
         xfault("mpl_get_row_bnds: i = %d; row number out of range\n",
alpar@1
   972
            i);
alpar@1
   973
      con = mpl->row[i];
alpar@1
   974
#if 0 /* 21/VII-2006 */
alpar@1
   975
      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
alpar@1
   976
         type = MPL_FR, lb = ub = 0.0;
alpar@1
   977
      else if (con->con->ubnd == NULL)
alpar@1
   978
         type = MPL_LO, lb = con->lbnd, ub = 0.0;
alpar@1
   979
      else if (con->con->lbnd == NULL)
alpar@1
   980
         type = MPL_UP, lb = 0.0, ub = con->ubnd;
alpar@1
   981
      else if (con->con->lbnd != con->con->ubnd)
alpar@1
   982
         type = MPL_DB, lb = con->lbnd, ub = con->ubnd;
alpar@1
   983
      else
alpar@1
   984
         type = MPL_FX, lb = ub = con->lbnd;
alpar@1
   985
#else
alpar@1
   986
      lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd);
alpar@1
   987
      ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd);
alpar@1
   988
      if (lb == -DBL_MAX && ub == +DBL_MAX)
alpar@1
   989
         type = MPL_FR, lb = ub = 0.0;
alpar@1
   990
      else if (ub == +DBL_MAX)
alpar@1
   991
         type = MPL_LO, ub = 0.0;
alpar@1
   992
      else if (lb == -DBL_MAX)
alpar@1
   993
         type = MPL_UP, lb = 0.0;
alpar@1
   994
      else if (con->con->lbnd != con->con->ubnd)
alpar@1
   995
         type = MPL_DB;
alpar@1
   996
      else
alpar@1
   997
         type = MPL_FX;
alpar@1
   998
#endif
alpar@1
   999
      if (_lb != NULL) *_lb = lb;
alpar@1
  1000
      if (_ub != NULL) *_ub = ub;
alpar@1
  1001
      return type;
alpar@1
  1002
}
alpar@1
  1003
alpar@1
  1004
/*----------------------------------------------------------------------
alpar@1
  1005
-- mpl_get_mat_row - obtain row of the constraint matrix.
alpar@1
  1006
--
alpar@1
  1007
-- *Synopsis*
alpar@1
  1008
--
alpar@1
  1009
-- #include "glpmpl.h"
alpar@1
  1010
-- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]);
alpar@1
  1011
--
alpar@1
  1012
-- *Description*
alpar@1
  1013
--
alpar@1
  1014
-- The routine mpl_get_mat_row stores column indices and numeric values
alpar@1
  1015
-- of constraint coefficients for the i-th row to locations ndx[1], ...,
alpar@1
  1016
-- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n
alpar@1
  1017
-- is number of (structural) non-zero constraint coefficients, and n is
alpar@1
  1018
-- number of columns in the problem.
alpar@1
  1019
--
alpar@1
  1020
-- If the parameter ndx is NULL, column indices are not stored. If the
alpar@1
  1021
-- parameter val is NULL, numeric values are not stored.
alpar@1
  1022
--
alpar@1
  1023
-- Note that free rows may have constant terms, which are not part of
alpar@1
  1024
-- the constraint matrix and therefore not reported by this routine. The
alpar@1
  1025
-- constant term of a particular row can be obtained, if necessary, via
alpar@1
  1026
-- the routine mpl_get_row_c0.
alpar@1
  1027
--
alpar@1
  1028
-- *Returns*
alpar@1
  1029
--
alpar@1
  1030
-- The routine mpl_get_mat_row returns len, which is length of i-th row
alpar@1
  1031
-- of the constraint matrix (i.e. number of non-zero coefficients). */
alpar@1
  1032
alpar@1
  1033
int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[])
alpar@1
  1034
{     FORMULA *term;
alpar@1
  1035
      int len = 0;
alpar@1
  1036
      if (mpl->phase != 3)
alpar@1
  1037
         xfault("mpl_get_mat_row: invalid call sequence\n");
alpar@1
  1038
      if (!(1 <= i && i <= mpl->m))
alpar@1
  1039
         xfault("mpl_get_mat_row: i = %d; row number out of range\n",
alpar@1
  1040
            i);
alpar@1
  1041
      for (term = mpl->row[i]->form; term != NULL; term = term->next)
alpar@1
  1042
      {  xassert(term->var != NULL);
alpar@1
  1043
         len++;
alpar@1
  1044
         xassert(len <= mpl->n);
alpar@1
  1045
         if (ndx != NULL) ndx[len] = term->var->j;
alpar@1
  1046
         if (val != NULL) val[len] = term->coef;
alpar@1
  1047
      }
alpar@1
  1048
      return len;
alpar@1
  1049
}
alpar@1
  1050
alpar@1
  1051
/*----------------------------------------------------------------------
alpar@1
  1052
-- mpl_get_row_c0 - obtain constant term of free row.
alpar@1
  1053
--
alpar@1
  1054
-- *Synopsis*
alpar@1
  1055
--
alpar@1
  1056
-- #include "glpmpl.h"
alpar@1
  1057
-- double mpl_get_row_c0(MPL *mpl, int i);
alpar@1
  1058
--
alpar@1
  1059
-- *Returns*
alpar@1
  1060
--
alpar@1
  1061
-- The routine mpl_get_row_c0 returns numeric value of constant term of
alpar@1
  1062
-- i-th row.
alpar@1
  1063
--
alpar@1
  1064
-- Note that only free rows may have non-zero constant terms. Therefore
alpar@1
  1065
-- if i-th row is not free, the routine returns zero. */
alpar@1
  1066
alpar@1
  1067
double mpl_get_row_c0(MPL *mpl, int i)
alpar@1
  1068
{     ELEMCON *con;
alpar@1
  1069
      double c0;
alpar@1
  1070
      if (mpl->phase != 3)
alpar@1
  1071
         xfault("mpl_get_row_c0: invalid call sequence\n");
alpar@1
  1072
      if (!(1 <= i && i <= mpl->m))
alpar@1
  1073
         xfault("mpl_get_row_c0: i = %d; row number out of range\n",
alpar@1
  1074
            i);
alpar@1
  1075
      con = mpl->row[i];
alpar@1
  1076
      if (con->con->lbnd == NULL && con->con->ubnd == NULL)
alpar@1
  1077
         c0 = - con->lbnd;
alpar@1
  1078
      else
alpar@1
  1079
         c0 = 0.0;
alpar@1
  1080
      return c0;
alpar@1
  1081
}
alpar@1
  1082
alpar@1
  1083
/*----------------------------------------------------------------------
alpar@1
  1084
-- mpl_get_col_name - obtain column name.
alpar@1
  1085
--
alpar@1
  1086
-- *Synopsis*
alpar@1
  1087
--
alpar@1
  1088
-- #include "glpmpl.h"
alpar@1
  1089
-- char *mpl_get_col_name(MPL *mpl, int j);
alpar@1
  1090
--
alpar@1
  1091
-- *Returns*
alpar@1
  1092
--
alpar@1
  1093
-- The routine mpl_get_col_name returns a pointer to internal buffer,
alpar@1
  1094
-- which contains symbolic name of j-th column of the problem. */
alpar@1
  1095
alpar@1
  1096
char *mpl_get_col_name(MPL *mpl, int j)
alpar@1
  1097
{     char *name = mpl->mpl_buf, *t;
alpar@1
  1098
      int len;
alpar@1
  1099
      if (mpl->phase != 3)
alpar@1
  1100
         xfault("mpl_get_col_name: invalid call sequence\n");
alpar@1
  1101
      if (!(1 <= j && j <= mpl->n))
alpar@1
  1102
         xfault("mpl_get_col_name: j = %d; column number out of range\n"
alpar@1
  1103
            , j);
alpar@1
  1104
      strcpy(name, mpl->col[j]->var->name);
alpar@1
  1105
      len = strlen(name);
alpar@1
  1106
      xassert(len <= 255);
alpar@1
  1107
      t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple);
alpar@1
  1108
      while (*t)
alpar@1
  1109
      {  if (len == 255) break;
alpar@1
  1110
         name[len++] = *t++;
alpar@1
  1111
      }
alpar@1
  1112
      name[len] = '\0';
alpar@1
  1113
      if (len == 255) strcpy(name+252, "...");
alpar@1
  1114
      xassert(strlen(name) <= 255);
alpar@1
  1115
      return name;
alpar@1
  1116
}
alpar@1
  1117
alpar@1
  1118
/*----------------------------------------------------------------------
alpar@1
  1119
-- mpl_get_col_kind - determine column kind.
alpar@1
  1120
--
alpar@1
  1121
-- *Synopsis*
alpar@1
  1122
--
alpar@1
  1123
-- #include "glpmpl.h"
alpar@1
  1124
-- int mpl_get_col_kind(MPL *mpl, int j);
alpar@1
  1125
--
alpar@1
  1126
-- *Returns*
alpar@1
  1127
--
alpar@1
  1128
-- The routine mpl_get_col_kind returns the kind of j-th column, which
alpar@1
  1129
-- can be one of the following:
alpar@1
  1130
--
alpar@1
  1131
-- MPL_NUM - continuous variable;
alpar@1
  1132
-- MPL_INT - integer variable;
alpar@1
  1133
-- MPL_BIN - binary variable.
alpar@1
  1134
--
alpar@1
  1135
-- Note that column kinds are defined independently on type and bounds
alpar@1
  1136
-- (reported by the routine mpl_get_col_bnds) of corresponding columns.
alpar@1
  1137
-- This means, in particular, that bounds of an integer column may be
alpar@1
  1138
-- fractional, or a binary column may have lower and upper bounds that
alpar@1
  1139
-- are not 0 and 1 (or it may have no lower/upper bound at all). */
alpar@1
  1140
alpar@1
  1141
int mpl_get_col_kind(MPL *mpl, int j)
alpar@1
  1142
{     int kind;
alpar@1
  1143
      if (mpl->phase != 3)
alpar@1
  1144
         xfault("mpl_get_col_kind: invalid call sequence\n");
alpar@1
  1145
      if (!(1 <= j && j <= mpl->n))
alpar@1
  1146
         xfault("mpl_get_col_kind: j = %d; column number out of range\n"
alpar@1
  1147
            , j);
alpar@1
  1148
      switch (mpl->col[j]->var->type)
alpar@1
  1149
      {  case A_NUMERIC:
alpar@1
  1150
            kind = MPL_NUM; break;
alpar@1
  1151
         case A_INTEGER:
alpar@1
  1152
            kind = MPL_INT; break;
alpar@1
  1153
         case A_BINARY:
alpar@1
  1154
            kind = MPL_BIN; break;
alpar@1
  1155
         default:
alpar@1
  1156
            xassert(mpl != mpl);
alpar@1
  1157
      }
alpar@1
  1158
      return kind;
alpar@1
  1159
}
alpar@1
  1160
alpar@1
  1161
/*----------------------------------------------------------------------
alpar@1
  1162
-- mpl_get_col_bnds - obtain column bounds.
alpar@1
  1163
--
alpar@1
  1164
-- *Synopsis*
alpar@1
  1165
--
alpar@1
  1166
-- #include "glpmpl.h"
alpar@1
  1167
-- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub);
alpar@1
  1168
--
alpar@1
  1169
-- *Description*
alpar@1
  1170
--
alpar@1
  1171
-- The routine mpl_get_col_bnds stores lower and upper bound of j-th
alpar@1
  1172
-- column of the problem to the locations, which the parameters lb and
alpar@1
  1173
-- ub point to, respectively. Besides the routine returns the type of
alpar@1
  1174
-- the j-th column.
alpar@1
  1175
--
alpar@1
  1176
-- If some of the parameters lb and ub is NULL, the corresponding bound
alpar@1
  1177
-- value is not stored.
alpar@1
  1178
--
alpar@1
  1179
-- Types and bounds have the following meaning:
alpar@1
  1180
--
alpar@1
  1181
--     Type         Bounds         Note
alpar@1
  1182
--    ------------------------------------------------------
alpar@1
  1183
--    MPL_FR   -inf <  x <  +inf   Free (unbounded) variable
alpar@1
  1184
--    MPL_LO     lb <= x <  +inf   Variable with lower bound
alpar@1
  1185
--    MPL_UP   -inf <  x <=  ub    Variable with upper bound
alpar@1
  1186
--    MPL_DB     lb <= x <=  ub    Double-bounded variable
alpar@1
  1187
--    MPL_FX           x  =  lb    Fixed variable
alpar@1
  1188
--
alpar@1
  1189
-- where x is individual variable corresponding to the j-th column.
alpar@1
  1190
--
alpar@1
  1191
-- If the column has no lower bound, *lb is set to zero; if the column
alpar@1
  1192
-- has no upper bound, *ub is set to zero; and if the column is of fixed
alpar@1
  1193
-- type, both *lb and *ub are set to the same value.
alpar@1
  1194
--
alpar@1
  1195
-- *Returns*
alpar@1
  1196
--
alpar@1
  1197
-- The routine returns the type of the j-th column as it is stated in
alpar@1
  1198
-- the table above. */
alpar@1
  1199
alpar@1
  1200
int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub)
alpar@1
  1201
{     ELEMVAR *var;
alpar@1
  1202
      int type;
alpar@1
  1203
      double lb, ub;
alpar@1
  1204
      if (mpl->phase != 3)
alpar@1
  1205
         xfault("mpl_get_col_bnds: invalid call sequence\n");
alpar@1
  1206
      if (!(1 <= j && j <= mpl->n))
alpar@1
  1207
         xfault("mpl_get_col_bnds: j = %d; column number out of range\n"
alpar@1
  1208
            , j);
alpar@1
  1209
      var = mpl->col[j];
alpar@1
  1210
#if 0 /* 21/VII-2006 */
alpar@1
  1211
      if (var->var->lbnd == NULL && var->var->ubnd == NULL)
alpar@1
  1212
         type = MPL_FR, lb = ub = 0.0;
alpar@1
  1213
      else if (var->var->ubnd == NULL)
alpar@1
  1214
         type = MPL_LO, lb = var->lbnd, ub = 0.0;
alpar@1
  1215
      else if (var->var->lbnd == NULL)
alpar@1
  1216
         type = MPL_UP, lb = 0.0, ub = var->ubnd;
alpar@1
  1217
      else if (var->var->lbnd != var->var->ubnd)
alpar@1
  1218
         type = MPL_DB, lb = var->lbnd, ub = var->ubnd;
alpar@1
  1219
      else
alpar@1
  1220
         type = MPL_FX, lb = ub = var->lbnd;
alpar@1
  1221
#else
alpar@1
  1222
      lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd);
alpar@1
  1223
      ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd);
alpar@1
  1224
      if (lb == -DBL_MAX && ub == +DBL_MAX)
alpar@1
  1225
         type = MPL_FR, lb = ub = 0.0;
alpar@1
  1226
      else if (ub == +DBL_MAX)
alpar@1
  1227
         type = MPL_LO, ub = 0.0;
alpar@1
  1228
      else if (lb == -DBL_MAX)
alpar@1
  1229
         type = MPL_UP, lb = 0.0;
alpar@1
  1230
      else if (var->var->lbnd != var->var->ubnd)
alpar@1
  1231
         type = MPL_DB;
alpar@1
  1232
      else
alpar@1
  1233
         type = MPL_FX;
alpar@1
  1234
#endif
alpar@1
  1235
      if (_lb != NULL) *_lb = lb;
alpar@1
  1236
      if (_ub != NULL) *_ub = ub;
alpar@1
  1237
      return type;
alpar@1
  1238
}
alpar@1
  1239
alpar@1
  1240
/*----------------------------------------------------------------------
alpar@1
  1241
-- mpl_has_solve_stmt - check if model has solve statement.
alpar@1
  1242
--
alpar@1
  1243
-- *Synopsis*
alpar@1
  1244
--
alpar@1
  1245
-- #include "glpmpl.h"
alpar@1
  1246
-- int mpl_has_solve_stmt(MPL *mpl);
alpar@1
  1247
--
alpar@1
  1248
-- *Returns*
alpar@1
  1249
--
alpar@1
  1250
-- If the model has the solve statement, the routine returns non-zero,
alpar@1
  1251
-- otherwise zero is returned. */
alpar@1
  1252
alpar@1
  1253
int mpl_has_solve_stmt(MPL *mpl)
alpar@1
  1254
{     if (mpl->phase != 3)
alpar@1
  1255
         xfault("mpl_has_solve_stmt: invalid call sequence\n");
alpar@1
  1256
      return mpl->flag_s;
alpar@1
  1257
}
alpar@1
  1258
alpar@1
  1259
#if 1 /* 15/V-2010 */
alpar@1
  1260
void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim,
alpar@1
  1261
      double dual)
alpar@1
  1262
{     /* store row (constraint/objective) solution components */
alpar@1
  1263
      xassert(mpl->phase == 3);
alpar@1
  1264
      xassert(1 <= i && i <= mpl->m);
alpar@1
  1265
      mpl->row[i]->stat = stat;
alpar@1
  1266
      mpl->row[i]->prim = prim;
alpar@1
  1267
      mpl->row[i]->dual = dual;
alpar@1
  1268
      return;
alpar@1
  1269
}
alpar@1
  1270
#endif
alpar@1
  1271
alpar@1
  1272
#if 1 /* 15/V-2010 */
alpar@1
  1273
void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim,
alpar@1
  1274
      double dual)
alpar@1
  1275
{     /* store column (variable) solution components */
alpar@1
  1276
      xassert(mpl->phase == 3);
alpar@1
  1277
      xassert(1 <= j && j <= mpl->n);
alpar@1
  1278
      mpl->col[j]->stat = stat;
alpar@1
  1279
      mpl->col[j]->prim = prim;
alpar@1
  1280
      mpl->col[j]->dual = dual;
alpar@1
  1281
      return;
alpar@1
  1282
}
alpar@1
  1283
#endif
alpar@1
  1284
alpar@1
  1285
#if 0 /* 15/V-2010 */
alpar@1
  1286
/*----------------------------------------------------------------------
alpar@1
  1287
-- mpl_put_col_value - store column value.
alpar@1
  1288
--
alpar@1
  1289
-- *Synopsis*
alpar@1
  1290
--
alpar@1
  1291
-- #include "glpmpl.h"
alpar@1
  1292
-- void mpl_put_col_value(MPL *mpl, int j, double val);
alpar@1
  1293
--
alpar@1
  1294
-- *Description*
alpar@1
  1295
--
alpar@1
  1296
-- The routine mpl_put_col_value stores numeric value of j-th column
alpar@1
  1297
-- into the translator database. It is assumed that the column value is
alpar@1
  1298
-- provided by the solver. */
alpar@1
  1299
alpar@1
  1300
void mpl_put_col_value(MPL *mpl, int j, double val)
alpar@1
  1301
{     if (mpl->phase != 3)
alpar@1
  1302
         xfault("mpl_put_col_value: invalid call sequence\n");
alpar@1
  1303
      if (!(1 <= j && j <= mpl->n))
alpar@1
  1304
         xfault(
alpar@1
  1305
         "mpl_put_col_value: j = %d; column number out of range\n", j);
alpar@1
  1306
      mpl->col[j]->prim = val;
alpar@1
  1307
      return;
alpar@1
  1308
}
alpar@1
  1309
#endif
alpar@1
  1310
alpar@1
  1311
/*----------------------------------------------------------------------
alpar@1
  1312
-- mpl_postsolve - postsolve model.
alpar@1
  1313
--
alpar@1
  1314
-- *Synopsis*
alpar@1
  1315
--
alpar@1
  1316
-- #include "glpmpl.h"
alpar@1
  1317
-- int mpl_postsolve(MPL *mpl);
alpar@1
  1318
--
alpar@1
  1319
-- *Description*
alpar@1
  1320
--
alpar@1
  1321
-- The routine mpl_postsolve performs postsolving of the model using
alpar@1
  1322
-- its description stored in the translator database. This phase means
alpar@1
  1323
-- executing statements, which follow the solve statement.
alpar@1
  1324
--
alpar@1
  1325
-- If this routine is used, it should be called once after the routine
alpar@1
  1326
-- mpl_generate and if the latter returned the code 3.
alpar@1
  1327
--
alpar@1
  1328
-- *Returns*
alpar@1
  1329
--
alpar@1
  1330
-- The routine mpl_postsolve returns one of the following codes:
alpar@1
  1331
--
alpar@1
  1332
-- 3 - model has been successfully postsolved.
alpar@1
  1333
-- 4 - processing failed due to some errors. In this case the calling
alpar@1
  1334
--     program should call the routine mpl_terminate to terminate model
alpar@1
  1335
--     processing. */
alpar@1
  1336
alpar@1
  1337
int mpl_postsolve(MPL *mpl)
alpar@1
  1338
{     if (!(mpl->phase == 3 && !mpl->flag_p))
alpar@1
  1339
         xfault("mpl_postsolve: invalid call sequence\n");
alpar@1
  1340
      /* set up error handler */
alpar@1
  1341
      if (setjmp(mpl->jump)) goto done;
alpar@1
  1342
      /* perform postsolving */
alpar@1
  1343
      postsolve_model(mpl);
alpar@1
  1344
      flush_output(mpl);
alpar@1
  1345
      /* postsolving phase has been finished */
alpar@1
  1346
      xprintf("Model has been successfully processed\n");
alpar@1
  1347
done: /* return to the calling program */
alpar@1
  1348
      return mpl->phase;
alpar@1
  1349
}
alpar@1
  1350
alpar@1
  1351
/*----------------------------------------------------------------------
alpar@1
  1352
-- mpl_terminate - free all resources used by translator.
alpar@1
  1353
--
alpar@1
  1354
-- *Synopsis*
alpar@1
  1355
--
alpar@1
  1356
-- #include "glpmpl.h"
alpar@1
  1357
-- void mpl_terminate(MPL *mpl);
alpar@1
  1358
--
alpar@1
  1359
-- *Description*
alpar@1
  1360
--
alpar@1
  1361
-- The routine mpl_terminate frees all the resources used by the GNU
alpar@1
  1362
-- MathProg translator. */
alpar@1
  1363
alpar@1
  1364
void mpl_terminate(MPL *mpl)
alpar@1
  1365
{     if (setjmp(mpl->jump)) xassert(mpl != mpl);
alpar@1
  1366
      switch (mpl->phase)
alpar@1
  1367
      {  case 0:
alpar@1
  1368
         case 1:
alpar@1
  1369
         case 2:
alpar@1
  1370
         case 3:
alpar@1
  1371
            /* there were no errors; clean the model content */
alpar@1
  1372
            clean_model(mpl);
alpar@1
  1373
            xassert(mpl->a_list == NULL);
alpar@1
  1374
#if 1 /* 11/II-2008 */
alpar@1
  1375
            xassert(mpl->dca == NULL);
alpar@1
  1376
#endif
alpar@1
  1377
            break;
alpar@1
  1378
         case 4:
alpar@1
  1379
            /* model processing has been finished due to error; delete
alpar@1
  1380
               search trees, which may be created for some arrays */
alpar@1
  1381
            {  ARRAY *a;
alpar@1
  1382
               for (a = mpl->a_list; a != NULL; a = a->next)
alpar@1
  1383
                  if (a->tree != NULL) avl_delete_tree(a->tree);
alpar@1
  1384
            }
alpar@1
  1385
#if 1 /* 11/II-2008 */
alpar@1
  1386
            free_dca(mpl);
alpar@1
  1387
#endif
alpar@1
  1388
            break;
alpar@1
  1389
         default:
alpar@1
  1390
            xassert(mpl != mpl);
alpar@1
  1391
      }
alpar@1
  1392
      /* delete the translator database */
alpar@1
  1393
      xfree(mpl->image);
alpar@1
  1394
      xfree(mpl->b_image);
alpar@1
  1395
      xfree(mpl->f_image);
alpar@1
  1396
      xfree(mpl->context);
alpar@1
  1397
      dmp_delete_pool(mpl->pool);
alpar@1
  1398
      avl_delete_tree(mpl->tree);
alpar@1
  1399
      dmp_delete_pool(mpl->strings);
alpar@1
  1400
      dmp_delete_pool(mpl->symbols);
alpar@1
  1401
      dmp_delete_pool(mpl->tuples);
alpar@1
  1402
      dmp_delete_pool(mpl->arrays);
alpar@1
  1403
      dmp_delete_pool(mpl->members);
alpar@1
  1404
      dmp_delete_pool(mpl->elemvars);
alpar@1
  1405
      dmp_delete_pool(mpl->formulae);
alpar@1
  1406
      dmp_delete_pool(mpl->elemcons);
alpar@1
  1407
      xfree(mpl->sym_buf);
alpar@1
  1408
      xfree(mpl->tup_buf);
alpar@1
  1409
      rng_delete_rand(mpl->rand);
alpar@1
  1410
      if (mpl->row != NULL) xfree(mpl->row);
alpar@1
  1411
      if (mpl->col != NULL) xfree(mpl->col);
alpar@1
  1412
      if (mpl->in_fp != NULL) xfclose(mpl->in_fp);
alpar@1
  1413
      if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout)
alpar@1
  1414
         xfclose(mpl->out_fp);
alpar@1
  1415
      if (mpl->out_file != NULL) xfree(mpl->out_file);
alpar@1
  1416
      if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp);
alpar@1
  1417
      if (mpl->prt_file != NULL) xfree(mpl->prt_file);
alpar@1
  1418
      if (mpl->mod_file != NULL) xfree(mpl->mod_file);
alpar@1
  1419
      xfree(mpl->mpl_buf);
alpar@1
  1420
      xfree(mpl);
alpar@1
  1421
      return;
alpar@1
  1422
}
alpar@1
  1423
alpar@1
  1424
/* eof */