lemon-project-template-glpk
comparison deps/glpk/src/glpmpl04.c @ 11:4fc6ad2fb8a6
Test GLPK in src/main.cc
author | Alpar Juttner <alpar@cs.elte.hu> |
---|---|
date | Sun, 06 Nov 2011 21:43:29 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:598f4cd2ff80 |
---|---|
1 /* glpmpl04.c */ | |
2 | |
3 /*********************************************************************** | |
4 * This code is part of GLPK (GNU Linear Programming Kit). | |
5 * | |
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, | |
7 * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, | |
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved. | |
9 * E-mail: <mao@gnu.org>. | |
10 * | |
11 * GLPK is free software: you can redistribute it and/or modify it | |
12 * under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation, either version 3 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT | |
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
19 * License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>. | |
23 ***********************************************************************/ | |
24 | |
25 #define _GLPSTD_ERRNO | |
26 #define _GLPSTD_STDIO | |
27 #include "glpmpl.h" | |
28 #define xfault xerror | |
29 #define dmp_create_poolx(size) dmp_create_pool() | |
30 | |
31 /**********************************************************************/ | |
32 /* * * GENERATING AND POSTSOLVING MODEL * * */ | |
33 /**********************************************************************/ | |
34 | |
35 /*---------------------------------------------------------------------- | |
36 -- alloc_content - allocate content arrays for all model objects. | |
37 -- | |
38 -- This routine allocates content arrays for all existing model objects | |
39 -- and thereby finalizes creating model. | |
40 -- | |
41 -- This routine must be called immediately after reading model section, | |
42 -- i.e. before reading data section or generating model. */ | |
43 | |
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 */ |