|
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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
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 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 |
|
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 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 |
|
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 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 |
|
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 |
|
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 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 |
|
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 |
|
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 |
|
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 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 |
|
415 void 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 |
|
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 |
|
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 |
|
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 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); |
|
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 |
|
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 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 */ |