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 */ |
---|