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 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 
alloc_content(MPL * mpl)44 void 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 
generate_model(MPL * mpl)108 void 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 
build_problem(MPL * mpl)125 void 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 
postsolve_model(MPL * mpl)209 void 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 
clean_model(MPL * mpl)232 void 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          mpl_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          mpl_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          mpl_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          mpl_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          mpl_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          mpl_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          mpl_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          mpl_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 
open_input(MPL * mpl,char * file)273 void 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          mpl_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 
read_char(MPL * mpl)310 int 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             mpl_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 
close_input(MPL * mpl)328 void 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 
open_output(MPL * mpl,char * file)342 void 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             mpl_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 
write_char(MPL * mpl,int c)363 void 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 
write_text(MPL * mpl,char * fmt,...)378 void 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 
flush_output(MPL * mpl)394 void 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             mpl_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 
mpl_error(MPL * mpl,char * fmt,...)415 void mpl_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 
warning(MPL * mpl,char * fmt,...)451 void 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 
mpl_initialize(void)495 MPL *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 
mpl_read_model(MPL * mpl,char * file,int skip_data)609 int 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          mpl_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             mpl_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);
647 skip: xprintf("%d line%s were read\n",
648          mpl->line, mpl->line == 1 ? "" : "s");
649       close_input(mpl);
650 done: /* 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 
mpl_read_data(MPL * mpl,char * file)680 int 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             mpl_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);
709 done: /* 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 
748 int 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");
762 done: /* 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 
786 char *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 
828 int 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 
847 int 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 
866 char *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 
905 int 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 
964 int 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 
1033 int 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 
1067 double 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 
1096 char *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 
1141 int 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 
1200 int 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 
1253 int 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 */
1260 void 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 */
1273 void 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 
1300 void 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 
1337 int 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");
1347 done: /* 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 
1364 void 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 */
1425