COIN-OR::LEMON - Graph Library

source: lemon-project-template-glpk/deps/glpk/src/glpmpl04.c @ 9:33de93886c88

subpack-glpk
Last change on this file since 9:33de93886c88 was 9:33de93886c88, checked in by Alpar Juttner <alpar@…>, 12 years ago

Import GLPK 4.47

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