alpar@9: /* glpmpl04.c */ alpar@9: alpar@9: /*********************************************************************** alpar@9: * This code is part of GLPK (GNU Linear Programming Kit). alpar@9: * alpar@9: * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, alpar@9: * 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, alpar@9: * Moscow Aviation Institute, Moscow, Russia. All rights reserved. alpar@9: * E-mail: . alpar@9: * alpar@9: * GLPK is free software: you can redistribute it and/or modify it alpar@9: * under the terms of the GNU General Public License as published by alpar@9: * the Free Software Foundation, either version 3 of the License, or alpar@9: * (at your option) any later version. alpar@9: * alpar@9: * GLPK is distributed in the hope that it will be useful, but WITHOUT alpar@9: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY alpar@9: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public alpar@9: * License for more details. alpar@9: * alpar@9: * You should have received a copy of the GNU General Public License alpar@9: * along with GLPK. If not, see . alpar@9: ***********************************************************************/ alpar@9: alpar@9: #define _GLPSTD_ERRNO alpar@9: #define _GLPSTD_STDIO alpar@9: #include "glpmpl.h" alpar@9: #define xfault xerror alpar@9: #define dmp_create_poolx(size) dmp_create_pool() alpar@9: alpar@9: /**********************************************************************/ alpar@9: /* * * GENERATING AND POSTSOLVING MODEL * * */ alpar@9: /**********************************************************************/ alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- alloc_content - allocate content arrays for all model objects. alpar@9: -- alpar@9: -- This routine allocates content arrays for all existing model objects alpar@9: -- and thereby finalizes creating model. alpar@9: -- alpar@9: -- This routine must be called immediately after reading model section, alpar@9: -- i.e. before reading data section or generating model. */ alpar@9: alpar@9: void alloc_content(MPL *mpl) alpar@9: { STATEMENT *stmt; alpar@9: /* walk through all model statements */ alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { switch (stmt->type) alpar@9: { case A_SET: alpar@9: /* model set */ alpar@9: xassert(stmt->u.set->array == NULL); alpar@9: stmt->u.set->array = create_array(mpl, A_ELEMSET, alpar@9: stmt->u.set->dim); alpar@9: break; alpar@9: case A_PARAMETER: alpar@9: /* model parameter */ alpar@9: xassert(stmt->u.par->array == NULL); alpar@9: switch (stmt->u.par->type) alpar@9: { case A_NUMERIC: alpar@9: case A_INTEGER: alpar@9: case A_BINARY: alpar@9: stmt->u.par->array = create_array(mpl, A_NUMERIC, alpar@9: stmt->u.par->dim); alpar@9: break; alpar@9: case A_SYMBOLIC: alpar@9: stmt->u.par->array = create_array(mpl, A_SYMBOLIC, alpar@9: stmt->u.par->dim); alpar@9: break; alpar@9: default: alpar@9: xassert(stmt != stmt); alpar@9: } alpar@9: break; alpar@9: case A_VARIABLE: alpar@9: /* model variable */ alpar@9: xassert(stmt->u.var->array == NULL); alpar@9: stmt->u.var->array = create_array(mpl, A_ELEMVAR, alpar@9: stmt->u.var->dim); alpar@9: break; alpar@9: case A_CONSTRAINT: alpar@9: /* model constraint/objective */ alpar@9: xassert(stmt->u.con->array == NULL); alpar@9: stmt->u.con->array = create_array(mpl, A_ELEMCON, alpar@9: stmt->u.con->dim); alpar@9: break; alpar@9: #if 1 /* 11/II-2008 */ alpar@9: case A_TABLE: alpar@9: #endif alpar@9: case A_SOLVE: alpar@9: case A_CHECK: alpar@9: case A_DISPLAY: alpar@9: case A_PRINTF: alpar@9: case A_FOR: alpar@9: /* functional statements have no content array */ alpar@9: break; alpar@9: default: alpar@9: xassert(stmt != stmt); alpar@9: } alpar@9: } alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- generate_model - generate model. alpar@9: -- alpar@9: -- This routine executes the model statements which precede the solve alpar@9: -- statement. */ alpar@9: alpar@9: void generate_model(MPL *mpl) alpar@9: { STATEMENT *stmt; alpar@9: xassert(!mpl->flag_p); alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { execute_statement(mpl, stmt); alpar@9: if (mpl->stmt->type == A_SOLVE) break; alpar@9: } alpar@9: mpl->stmt = stmt; alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- build_problem - build problem instance. alpar@9: -- alpar@9: -- This routine builds lists of rows and columns for problem instance, alpar@9: -- which corresponds to the generated model. */ alpar@9: alpar@9: void build_problem(MPL *mpl) alpar@9: { STATEMENT *stmt; alpar@9: MEMBER *memb; alpar@9: VARIABLE *v; alpar@9: CONSTRAINT *c; alpar@9: FORMULA *t; alpar@9: int i, j; alpar@9: xassert(mpl->m == 0); alpar@9: xassert(mpl->n == 0); alpar@9: xassert(mpl->row == NULL); alpar@9: xassert(mpl->col == NULL); alpar@9: /* check that all elemental variables has zero column numbers */ alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { if (stmt->type == A_VARIABLE) alpar@9: { v = stmt->u.var; alpar@9: for (memb = v->array->head; memb != NULL; memb = memb->next) alpar@9: xassert(memb->value.var->j == 0); alpar@9: } alpar@9: } alpar@9: /* assign row numbers to elemental constraints and objectives */ alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { if (stmt->type == A_CONSTRAINT) alpar@9: { c = stmt->u.con; alpar@9: for (memb = c->array->head; memb != NULL; memb = memb->next) alpar@9: { xassert(memb->value.con->i == 0); alpar@9: memb->value.con->i = ++mpl->m; alpar@9: /* walk through linear form and mark elemental variables, alpar@9: which are referenced at least once */ alpar@9: for (t = memb->value.con->form; t != NULL; t = t->next) alpar@9: { xassert(t->var != NULL); alpar@9: t->var->memb->value.var->j = -1; alpar@9: } alpar@9: } alpar@9: } alpar@9: } alpar@9: /* assign column numbers to marked elemental variables */ alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { if (stmt->type == A_VARIABLE) alpar@9: { v = stmt->u.var; alpar@9: for (memb = v->array->head; memb != NULL; memb = memb->next) alpar@9: if (memb->value.var->j != 0) memb->value.var->j = alpar@9: ++mpl->n; alpar@9: } alpar@9: } alpar@9: /* build list of rows */ alpar@9: mpl->row = xcalloc(1+mpl->m, sizeof(ELEMCON *)); alpar@9: for (i = 1; i <= mpl->m; i++) mpl->row[i] = NULL; alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { if (stmt->type == A_CONSTRAINT) alpar@9: { c = stmt->u.con; alpar@9: for (memb = c->array->head; memb != NULL; memb = memb->next) alpar@9: { i = memb->value.con->i; alpar@9: xassert(1 <= i && i <= mpl->m); alpar@9: xassert(mpl->row[i] == NULL); alpar@9: mpl->row[i] = memb->value.con; alpar@9: } alpar@9: } alpar@9: } alpar@9: for (i = 1; i <= mpl->m; i++) xassert(mpl->row[i] != NULL); alpar@9: /* build list of columns */ alpar@9: mpl->col = xcalloc(1+mpl->n, sizeof(ELEMVAR *)); alpar@9: for (j = 1; j <= mpl->n; j++) mpl->col[j] = NULL; alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: { if (stmt->type == A_VARIABLE) alpar@9: { v = stmt->u.var; alpar@9: for (memb = v->array->head; memb != NULL; memb = memb->next) alpar@9: { j = memb->value.var->j; alpar@9: if (j == 0) continue; alpar@9: xassert(1 <= j && j <= mpl->n); alpar@9: xassert(mpl->col[j] == NULL); alpar@9: mpl->col[j] = memb->value.var; alpar@9: } alpar@9: } alpar@9: } alpar@9: for (j = 1; j <= mpl->n; j++) xassert(mpl->col[j] != NULL); alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- postsolve_model - postsolve model. alpar@9: -- alpar@9: -- This routine executes the model statements which follow the solve alpar@9: -- statement. */ alpar@9: alpar@9: void postsolve_model(MPL *mpl) alpar@9: { STATEMENT *stmt; alpar@9: xassert(!mpl->flag_p); alpar@9: mpl->flag_p = 1; alpar@9: for (stmt = mpl->stmt; stmt != NULL; stmt = stmt->next) alpar@9: execute_statement(mpl, stmt); alpar@9: mpl->stmt = NULL; alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- clean_model - clean model content. alpar@9: -- alpar@9: -- This routine cleans the model content that assumes deleting all stuff alpar@9: -- dynamically allocated on generating/postsolving phase. alpar@9: -- alpar@9: -- Actually cleaning model content is not needed. This function is used alpar@9: -- mainly to be sure that there were no logical errors on using dynamic alpar@9: -- memory pools during the generation phase. alpar@9: -- alpar@9: -- NOTE: This routine must not be called if any errors were detected on alpar@9: -- the generation phase. */ alpar@9: alpar@9: void clean_model(MPL *mpl) alpar@9: { STATEMENT *stmt; alpar@9: for (stmt = mpl->model; stmt != NULL; stmt = stmt->next) alpar@9: clean_statement(mpl, stmt); alpar@9: /* check that all atoms have been returned to their pools */ alpar@9: if (dmp_in_use(mpl->strings).lo != 0) alpar@9: error(mpl, "internal logic error: %d string segment(s) were lo" alpar@9: "st", dmp_in_use(mpl->strings).lo); alpar@9: if (dmp_in_use(mpl->symbols).lo != 0) alpar@9: error(mpl, "internal logic error: %d symbol(s) were lost", alpar@9: dmp_in_use(mpl->symbols).lo); alpar@9: if (dmp_in_use(mpl->tuples).lo != 0) alpar@9: error(mpl, "internal logic error: %d n-tuple component(s) were" alpar@9: " lost", dmp_in_use(mpl->tuples).lo); alpar@9: if (dmp_in_use(mpl->arrays).lo != 0) alpar@9: error(mpl, "internal logic error: %d array(s) were lost", alpar@9: dmp_in_use(mpl->arrays).lo); alpar@9: if (dmp_in_use(mpl->members).lo != 0) alpar@9: error(mpl, "internal logic error: %d array member(s) were lost" alpar@9: , dmp_in_use(mpl->members).lo); alpar@9: if (dmp_in_use(mpl->elemvars).lo != 0) alpar@9: error(mpl, "internal logic error: %d elemental variable(s) wer" alpar@9: "e lost", dmp_in_use(mpl->elemvars).lo); alpar@9: if (dmp_in_use(mpl->formulae).lo != 0) alpar@9: error(mpl, "internal logic error: %d linear term(s) were lost", alpar@9: dmp_in_use(mpl->formulae).lo); alpar@9: if (dmp_in_use(mpl->elemcons).lo != 0) alpar@9: error(mpl, "internal logic error: %d elemental constraint(s) w" alpar@9: "ere lost", dmp_in_use(mpl->elemcons).lo); alpar@9: return; alpar@9: } alpar@9: alpar@9: /**********************************************************************/ alpar@9: /* * * INPUT/OUTPUT * * */ alpar@9: /**********************************************************************/ alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- open_input - open input text file. alpar@9: -- alpar@9: -- This routine opens the input text file for scanning. */ alpar@9: alpar@9: void open_input(MPL *mpl, char *file) alpar@9: { mpl->line = 0; alpar@9: mpl->c = '\n'; alpar@9: mpl->token = 0; alpar@9: mpl->imlen = 0; alpar@9: mpl->image[0] = '\0'; alpar@9: mpl->value = 0.0; alpar@9: mpl->b_token = T_EOF; alpar@9: mpl->b_imlen = 0; alpar@9: mpl->b_image[0] = '\0'; alpar@9: mpl->b_value = 0.0; alpar@9: mpl->f_dots = 0; alpar@9: mpl->f_scan = 0; alpar@9: mpl->f_token = 0; alpar@9: mpl->f_imlen = 0; alpar@9: mpl->f_image[0] = '\0'; alpar@9: mpl->f_value = 0.0; alpar@9: memset(mpl->context, ' ', CONTEXT_SIZE); alpar@9: mpl->c_ptr = 0; alpar@9: xassert(mpl->in_fp == NULL); alpar@9: mpl->in_fp = xfopen(file, "r"); alpar@9: if (mpl->in_fp == NULL) alpar@9: error(mpl, "unable to open %s - %s", file, xerrmsg()); alpar@9: mpl->in_file = file; alpar@9: /* scan the very first character */ alpar@9: get_char(mpl); alpar@9: /* scan the very first token */ alpar@9: get_token(mpl); alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- read_char - read next character from input text file. alpar@9: -- alpar@9: -- This routine returns a next ASCII character read from the input text alpar@9: -- file. If the end of file has been reached, EOF is returned. */ alpar@9: alpar@9: int read_char(MPL *mpl) alpar@9: { int c; alpar@9: xassert(mpl->in_fp != NULL); alpar@9: c = xfgetc(mpl->in_fp); alpar@9: if (c < 0) alpar@9: { if (xferror(mpl->in_fp)) alpar@9: error(mpl, "read error on %s - %s", mpl->in_file, alpar@9: xerrmsg()); alpar@9: c = EOF; alpar@9: } alpar@9: return c; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- close_input - close input text file. alpar@9: -- alpar@9: -- This routine closes the input text file. */ alpar@9: alpar@9: void close_input(MPL *mpl) alpar@9: { xassert(mpl->in_fp != NULL); alpar@9: xfclose(mpl->in_fp); alpar@9: mpl->in_fp = NULL; alpar@9: mpl->in_file = NULL; alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- open_output - open output text file. alpar@9: -- alpar@9: -- This routine opens the output text file for writing data produced by alpar@9: -- display and printf statements. */ alpar@9: alpar@9: void open_output(MPL *mpl, char *file) alpar@9: { xassert(mpl->out_fp == NULL); alpar@9: if (file == NULL) alpar@9: { file = ""; alpar@9: mpl->out_fp = (void *)stdout; alpar@9: } alpar@9: else alpar@9: { mpl->out_fp = xfopen(file, "w"); alpar@9: if (mpl->out_fp == NULL) alpar@9: error(mpl, "unable to create %s - %s", file, xerrmsg()); alpar@9: } alpar@9: mpl->out_file = xmalloc(strlen(file)+1); alpar@9: strcpy(mpl->out_file, file); alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- write_char - write next character to output text file. alpar@9: -- alpar@9: -- This routine writes an ASCII character to the output text file. */ alpar@9: alpar@9: void write_char(MPL *mpl, int c) alpar@9: { xassert(mpl->out_fp != NULL); alpar@9: if (mpl->out_fp == (void *)stdout) alpar@9: xprintf("%c", c); alpar@9: else alpar@9: xfprintf(mpl->out_fp, "%c", c); alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- write_text - format and write text to output text file. alpar@9: -- alpar@9: -- This routine formats a text using the format control string and then alpar@9: -- writes this text to the output text file. */ alpar@9: alpar@9: void write_text(MPL *mpl, char *fmt, ...) alpar@9: { va_list arg; alpar@9: char buf[OUTBUF_SIZE], *c; alpar@9: va_start(arg, fmt); alpar@9: vsprintf(buf, fmt, arg); alpar@9: xassert(strlen(buf) < sizeof(buf)); alpar@9: va_end(arg); alpar@9: for (c = buf; *c != '\0'; c++) write_char(mpl, *c); alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- flush_output - finalize writing data to output text file. alpar@9: -- alpar@9: -- This routine finalizes writing data to the output text file. */ alpar@9: alpar@9: void flush_output(MPL *mpl) alpar@9: { xassert(mpl->out_fp != NULL); alpar@9: if (mpl->out_fp != (void *)stdout) alpar@9: { xfflush(mpl->out_fp); alpar@9: if (xferror(mpl->out_fp)) alpar@9: error(mpl, "write error on %s - %s", mpl->out_file, alpar@9: xerrmsg()); alpar@9: } alpar@9: return; alpar@9: } alpar@9: alpar@9: /**********************************************************************/ alpar@9: /* * * SOLVER INTERFACE * * */ alpar@9: /**********************************************************************/ alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- error - print error message and terminate model processing. alpar@9: -- alpar@9: -- This routine formats and prints an error message and then terminates alpar@9: -- model processing. */ alpar@9: alpar@9: void error(MPL *mpl, char *fmt, ...) alpar@9: { va_list arg; alpar@9: char msg[4095+1]; alpar@9: va_start(arg, fmt); alpar@9: vsprintf(msg, fmt, arg); alpar@9: xassert(strlen(msg) < sizeof(msg)); alpar@9: va_end(arg); alpar@9: switch (mpl->phase) alpar@9: { case 1: alpar@9: case 2: alpar@9: /* translation phase */ alpar@9: xprintf("%s:%d: %s\n", alpar@9: mpl->in_file == NULL ? "(unknown)" : mpl->in_file, alpar@9: mpl->line, msg); alpar@9: print_context(mpl); alpar@9: break; alpar@9: case 3: alpar@9: /* generation/postsolve phase */ alpar@9: xprintf("%s:%d: %s\n", alpar@9: mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file, alpar@9: mpl->stmt == NULL ? 0 : mpl->stmt->line, msg); alpar@9: break; alpar@9: default: alpar@9: xassert(mpl != mpl); alpar@9: } alpar@9: mpl->phase = 4; alpar@9: longjmp(mpl->jump, 1); alpar@9: /* no return */ alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- warning - print warning message and continue model processing. alpar@9: -- alpar@9: -- This routine formats and prints a warning message and returns to the alpar@9: -- calling program. */ alpar@9: alpar@9: void warning(MPL *mpl, char *fmt, ...) alpar@9: { va_list arg; alpar@9: char msg[4095+1]; alpar@9: va_start(arg, fmt); alpar@9: vsprintf(msg, fmt, arg); alpar@9: xassert(strlen(msg) < sizeof(msg)); alpar@9: va_end(arg); alpar@9: switch (mpl->phase) alpar@9: { case 1: alpar@9: case 2: alpar@9: /* translation phase */ alpar@9: xprintf("%s:%d: warning: %s\n", alpar@9: mpl->in_file == NULL ? "(unknown)" : mpl->in_file, alpar@9: mpl->line, msg); alpar@9: break; alpar@9: case 3: alpar@9: /* generation/postsolve phase */ alpar@9: xprintf("%s:%d: warning: %s\n", alpar@9: mpl->mod_file == NULL ? "(unknown)" : mpl->mod_file, alpar@9: mpl->stmt == NULL ? 0 : mpl->stmt->line, msg); alpar@9: break; alpar@9: default: alpar@9: xassert(mpl != mpl); alpar@9: } alpar@9: return; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_initialize - create and initialize translator database. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- MPL *mpl_initialize(void); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_initialize creates and initializes the database used alpar@9: -- by the GNU MathProg translator. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine returns a pointer to the database created. */ alpar@9: alpar@9: MPL *mpl_initialize(void) alpar@9: { MPL *mpl; alpar@9: mpl = xmalloc(sizeof(MPL)); alpar@9: /* scanning segment */ alpar@9: mpl->line = 0; alpar@9: mpl->c = 0; alpar@9: mpl->token = 0; alpar@9: mpl->imlen = 0; alpar@9: mpl->image = xcalloc(MAX_LENGTH+1, sizeof(char)); alpar@9: mpl->image[0] = '\0'; alpar@9: mpl->value = 0.0; alpar@9: mpl->b_token = 0; alpar@9: mpl->b_imlen = 0; alpar@9: mpl->b_image = xcalloc(MAX_LENGTH+1, sizeof(char)); alpar@9: mpl->b_image[0] = '\0'; alpar@9: mpl->b_value = 0.0; alpar@9: mpl->f_dots = 0; alpar@9: mpl->f_scan = 0; alpar@9: mpl->f_token = 0; alpar@9: mpl->f_imlen = 0; alpar@9: mpl->f_image = xcalloc(MAX_LENGTH+1, sizeof(char)); alpar@9: mpl->f_image[0] = '\0'; alpar@9: mpl->f_value = 0.0; alpar@9: mpl->context = xcalloc(CONTEXT_SIZE, sizeof(char)); alpar@9: memset(mpl->context, ' ', CONTEXT_SIZE); alpar@9: mpl->c_ptr = 0; alpar@9: mpl->flag_d = 0; alpar@9: /* translating segment */ alpar@9: mpl->pool = dmp_create_poolx(0); alpar@9: mpl->tree = avl_create_tree(avl_strcmp, NULL); alpar@9: mpl->model = NULL; alpar@9: mpl->flag_x = 0; alpar@9: mpl->as_within = 0; alpar@9: mpl->as_in = 0; alpar@9: mpl->as_binary = 0; alpar@9: mpl->flag_s = 0; alpar@9: /* common segment */ alpar@9: mpl->strings = dmp_create_poolx(sizeof(STRING)); alpar@9: mpl->symbols = dmp_create_poolx(sizeof(SYMBOL)); alpar@9: mpl->tuples = dmp_create_poolx(sizeof(TUPLE)); alpar@9: mpl->arrays = dmp_create_poolx(sizeof(ARRAY)); alpar@9: mpl->members = dmp_create_poolx(sizeof(MEMBER)); alpar@9: mpl->elemvars = dmp_create_poolx(sizeof(ELEMVAR)); alpar@9: mpl->formulae = dmp_create_poolx(sizeof(FORMULA)); alpar@9: mpl->elemcons = dmp_create_poolx(sizeof(ELEMCON)); alpar@9: mpl->a_list = NULL; alpar@9: mpl->sym_buf = xcalloc(255+1, sizeof(char)); alpar@9: mpl->sym_buf[0] = '\0'; alpar@9: mpl->tup_buf = xcalloc(255+1, sizeof(char)); alpar@9: mpl->tup_buf[0] = '\0'; alpar@9: /* generating/postsolving segment */ alpar@9: mpl->rand = rng_create_rand(); alpar@9: mpl->flag_p = 0; alpar@9: mpl->stmt = NULL; alpar@9: #if 1 /* 11/II-2008 */ alpar@9: mpl->dca = NULL; alpar@9: #endif alpar@9: mpl->m = 0; alpar@9: mpl->n = 0; alpar@9: mpl->row = NULL; alpar@9: mpl->col = NULL; alpar@9: /* input/output segment */ alpar@9: mpl->in_fp = NULL; alpar@9: mpl->in_file = NULL; alpar@9: mpl->out_fp = NULL; alpar@9: mpl->out_file = NULL; alpar@9: mpl->prt_fp = NULL; alpar@9: mpl->prt_file = NULL; alpar@9: /* solver interface segment */ alpar@9: if (setjmp(mpl->jump)) xassert(mpl != mpl); alpar@9: mpl->phase = 0; alpar@9: mpl->mod_file = NULL; alpar@9: mpl->mpl_buf = xcalloc(255+1, sizeof(char)); alpar@9: mpl->mpl_buf[0] = '\0'; alpar@9: return mpl; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_read_model - read model section and optional data section. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_read_model(MPL *mpl, char *file, int skip_data); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_read_model reads model section and optionally data alpar@9: -- section, which may follow the model section, from the text file, alpar@9: -- whose name is the character string file, performs translating model alpar@9: -- statements and data blocks, and stores all the information in the alpar@9: -- translator database. alpar@9: -- alpar@9: -- The parameter skip_data is a flag. If the input file contains the alpar@9: -- data section and this flag is set, the data section is not read as alpar@9: -- if there were no data section and a warning message is issued. This alpar@9: -- allows reading the data section from another input file. alpar@9: -- alpar@9: -- This routine should be called once after the routine mpl_initialize alpar@9: -- and before other API routines. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_read_model returns one the following codes: alpar@9: -- alpar@9: -- 1 - translation successful. The input text file contains only model alpar@9: -- section. In this case the calling program may call the routine alpar@9: -- mpl_read_data to read data section from another file. alpar@9: -- 2 - translation successful. The input text file contains both model alpar@9: -- and data section. alpar@9: -- 4 - processing failed due to some errors. In this case the calling alpar@9: -- program should call the routine mpl_terminate to terminate model alpar@9: -- processing. */ alpar@9: alpar@9: int mpl_read_model(MPL *mpl, char *file, int skip_data) alpar@9: { if (mpl->phase != 0) alpar@9: xfault("mpl_read_model: invalid call sequence\n"); alpar@9: if (file == NULL) alpar@9: xfault("mpl_read_model: no input filename specified\n"); alpar@9: /* set up error handler */ alpar@9: if (setjmp(mpl->jump)) goto done; alpar@9: /* translate model section */ alpar@9: mpl->phase = 1; alpar@9: xprintf("Reading model section from %s...\n", file); alpar@9: open_input(mpl, file); alpar@9: model_section(mpl); alpar@9: if (mpl->model == NULL) alpar@9: error(mpl, "empty model section not allowed"); alpar@9: /* save name of the input text file containing model section for alpar@9: error diagnostics during the generation phase */ alpar@9: mpl->mod_file = xcalloc(strlen(file)+1, sizeof(char)); alpar@9: strcpy(mpl->mod_file, mpl->in_file); alpar@9: /* allocate content arrays for all model objects */ alpar@9: alloc_content(mpl); alpar@9: /* optional data section may begin with the keyword 'data' */ alpar@9: if (is_keyword(mpl, "data")) alpar@9: { if (skip_data) alpar@9: { warning(mpl, "data section ignored"); alpar@9: goto skip; alpar@9: } alpar@9: mpl->flag_d = 1; alpar@9: get_token(mpl /* data */); alpar@9: if (mpl->token != T_SEMICOLON) alpar@9: error(mpl, "semicolon missing where expected"); alpar@9: get_token(mpl /* ; */); alpar@9: /* translate data section */ alpar@9: mpl->phase = 2; alpar@9: xprintf("Reading data section from %s...\n", file); alpar@9: data_section(mpl); alpar@9: } alpar@9: /* process end statement */ alpar@9: end_statement(mpl); alpar@9: skip: xprintf("%d line%s were read\n", alpar@9: mpl->line, mpl->line == 1 ? "" : "s"); alpar@9: close_input(mpl); alpar@9: done: /* return to the calling program */ alpar@9: return mpl->phase; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_read_data - read data section. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_read_data(MPL *mpl, char *file); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_read_data reads data section from the text file, alpar@9: -- whose name is the character string file, performs translating data alpar@9: -- blocks, and stores the data read in the translator database. alpar@9: -- alpar@9: -- If this routine is used, it should be called once after the routine alpar@9: -- mpl_read_model and if the latter returned the code 1. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_read_data returns one of the following codes: alpar@9: -- alpar@9: -- 2 - data section has been successfully processed. alpar@9: -- 4 - processing failed due to some errors. In this case the calling alpar@9: -- program should call the routine mpl_terminate to terminate model alpar@9: -- processing. */ alpar@9: alpar@9: int mpl_read_data(MPL *mpl, char *file) alpar@9: #if 0 /* 02/X-2008 */ alpar@9: { if (mpl->phase != 1) alpar@9: #else alpar@9: { if (!(mpl->phase == 1 || mpl->phase == 2)) alpar@9: #endif alpar@9: xfault("mpl_read_data: invalid call sequence\n"); alpar@9: if (file == NULL) alpar@9: xfault("mpl_read_data: no input filename specified\n"); alpar@9: /* set up error handler */ alpar@9: if (setjmp(mpl->jump)) goto done; alpar@9: /* process data section */ alpar@9: mpl->phase = 2; alpar@9: xprintf("Reading data section from %s...\n", file); alpar@9: mpl->flag_d = 1; alpar@9: open_input(mpl, file); alpar@9: /* in this case the keyword 'data' is optional */ alpar@9: if (is_literal(mpl, "data")) alpar@9: { get_token(mpl /* data */); alpar@9: if (mpl->token != T_SEMICOLON) alpar@9: error(mpl, "semicolon missing where expected"); alpar@9: get_token(mpl /* ; */); alpar@9: } alpar@9: data_section(mpl); alpar@9: /* process end statement */ alpar@9: end_statement(mpl); alpar@9: xprintf("%d line%s were read\n", alpar@9: mpl->line, mpl->line == 1 ? "" : "s"); alpar@9: close_input(mpl); alpar@9: done: /* return to the calling program */ alpar@9: return mpl->phase; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_generate - generate model. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_generate(MPL *mpl, char *file); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_generate generates the model using its description alpar@9: -- stored in the translator database. This phase means generating all alpar@9: -- variables, constraints, and objectives, executing check and display alpar@9: -- statements, which precede the solve statement (if it is presented), alpar@9: -- and building the problem instance. alpar@9: -- alpar@9: -- The character string file specifies the name of output text file, to alpar@9: -- which output produced by display statements should be written. It is alpar@9: -- allowed to specify NULL, in which case the output goes to stdout via alpar@9: -- the routine print. alpar@9: -- alpar@9: -- This routine should be called once after the routine mpl_read_model alpar@9: -- or mpl_read_data and if one of the latters returned the code 2. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_generate returns one of the following codes: alpar@9: -- alpar@9: -- 3 - model has been successfully generated. In this case the calling alpar@9: -- program may call other api routines to obtain components of the alpar@9: -- problem instance from the translator database. alpar@9: -- 4 - processing failed due to some errors. In this case the calling alpar@9: -- program should call the routine mpl_terminate to terminate model alpar@9: -- processing. */ alpar@9: alpar@9: int mpl_generate(MPL *mpl, char *file) alpar@9: { if (!(mpl->phase == 1 || mpl->phase == 2)) alpar@9: xfault("mpl_generate: invalid call sequence\n"); alpar@9: /* set up error handler */ alpar@9: if (setjmp(mpl->jump)) goto done; alpar@9: /* generate model */ alpar@9: mpl->phase = 3; alpar@9: open_output(mpl, file); alpar@9: generate_model(mpl); alpar@9: flush_output(mpl); alpar@9: /* build problem instance */ alpar@9: build_problem(mpl); alpar@9: /* generation phase has been finished */ alpar@9: xprintf("Model has been successfully generated\n"); alpar@9: done: /* return to the calling program */ alpar@9: return mpl->phase; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_prob_name - obtain problem (model) name. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- char *mpl_get_prob_name(MPL *mpl); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_prob_name returns a pointer to internal buffer, alpar@9: -- which contains symbolic name of the problem (model). alpar@9: -- alpar@9: -- *Note* alpar@9: -- alpar@9: -- Currently MathProg has no feature to assign a symbolic name to the alpar@9: -- model. Therefore the routine mpl_get_prob_name tries to construct alpar@9: -- such name using the name of input text file containing model section, alpar@9: -- although this is not a good idea (due to portability problems). */ alpar@9: alpar@9: char *mpl_get_prob_name(MPL *mpl) alpar@9: { char *name = mpl->mpl_buf; alpar@9: char *file = mpl->mod_file; alpar@9: int k; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_prob_name: invalid call sequence\n"); alpar@9: for (;;) alpar@9: { if (strchr(file, '/') != NULL) alpar@9: file = strchr(file, '/') + 1; alpar@9: else if (strchr(file, '\\') != NULL) alpar@9: file = strchr(file, '\\') + 1; alpar@9: else if (strchr(file, ':') != NULL) alpar@9: file = strchr(file, ':') + 1; alpar@9: else alpar@9: break; alpar@9: } alpar@9: for (k = 0; ; k++) alpar@9: { if (k == 255) break; alpar@9: if (!(isalnum((unsigned char)*file) || *file == '_')) break; alpar@9: name[k] = *file++; alpar@9: } alpar@9: if (k == 0) alpar@9: strcpy(name, "Unknown"); alpar@9: else alpar@9: name[k] = '\0'; alpar@9: xassert(strlen(name) <= 255); alpar@9: return name; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_num_rows - determine number of rows. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_num_rows(MPL *mpl); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_num_rows returns total number of rows in the alpar@9: -- problem, where each row is an individual constraint or objective. */ alpar@9: alpar@9: int mpl_get_num_rows(MPL *mpl) alpar@9: { if (mpl->phase != 3) alpar@9: xfault("mpl_get_num_rows: invalid call sequence\n"); alpar@9: return mpl->m; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_num_cols - determine number of columns. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_num_cols(MPL *mpl); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_num_cols returns total number of columns in the alpar@9: -- problem, where each column is an individual variable. */ alpar@9: alpar@9: int mpl_get_num_cols(MPL *mpl) alpar@9: { if (mpl->phase != 3) alpar@9: xfault("mpl_get_num_cols: invalid call sequence\n"); alpar@9: return mpl->n; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_row_name - obtain row name. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- char *mpl_get_row_name(MPL *mpl, int i); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_row_name returns a pointer to internal buffer, alpar@9: -- which contains symbolic name of i-th row of the problem. */ alpar@9: alpar@9: char *mpl_get_row_name(MPL *mpl, int i) alpar@9: { char *name = mpl->mpl_buf, *t; alpar@9: int len; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_row_name: invalid call sequence\n"); alpar@9: if (!(1 <= i && i <= mpl->m)) alpar@9: xfault("mpl_get_row_name: i = %d; row number out of range\n", alpar@9: i); alpar@9: strcpy(name, mpl->row[i]->con->name); alpar@9: len = strlen(name); alpar@9: xassert(len <= 255); alpar@9: t = format_tuple(mpl, '[', mpl->row[i]->memb->tuple); alpar@9: while (*t) alpar@9: { if (len == 255) break; alpar@9: name[len++] = *t++; alpar@9: } alpar@9: name[len] = '\0'; alpar@9: if (len == 255) strcpy(name+252, "..."); alpar@9: xassert(strlen(name) <= 255); alpar@9: return name; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_row_kind - determine row kind. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_row_kind(MPL *mpl, int i); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_row_kind returns the kind of i-th row, which can alpar@9: -- be one of the following: alpar@9: -- alpar@9: -- MPL_ST - non-free (constraint) row; alpar@9: -- MPL_MIN - free (objective) row to be minimized; alpar@9: -- MPL_MAX - free (objective) row to be maximized. */ alpar@9: alpar@9: int mpl_get_row_kind(MPL *mpl, int i) alpar@9: { int kind; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_row_kind: invalid call sequence\n"); alpar@9: if (!(1 <= i && i <= mpl->m)) alpar@9: xfault("mpl_get_row_kind: i = %d; row number out of range\n", alpar@9: i); alpar@9: switch (mpl->row[i]->con->type) alpar@9: { case A_CONSTRAINT: alpar@9: kind = MPL_ST; break; alpar@9: case A_MINIMIZE: alpar@9: kind = MPL_MIN; break; alpar@9: case A_MAXIMIZE: alpar@9: kind = MPL_MAX; break; alpar@9: default: alpar@9: xassert(mpl != mpl); alpar@9: } alpar@9: return kind; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_row_bnds - obtain row bounds. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_row_bnds(MPL *mpl, int i, double *lb, double *ub); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_get_row_bnds stores lower and upper bounds of i-th alpar@9: -- row of the problem to the locations, which the parameters lb and ub alpar@9: -- point to, respectively. Besides the routine returns the type of the alpar@9: -- i-th row. alpar@9: -- alpar@9: -- If some of the parameters lb and ub is NULL, the corresponding bound alpar@9: -- value is not stored. alpar@9: -- alpar@9: -- Types and bounds have the following meaning: alpar@9: -- alpar@9: -- Type Bounds Note alpar@9: -- ----------------------------------------------------------- alpar@9: -- MPL_FR -inf < f(x) < +inf Free linear form alpar@9: -- MPL_LO lb <= f(x) < +inf Inequality f(x) >= lb alpar@9: -- MPL_UP -inf < f(x) <= ub Inequality f(x) <= ub alpar@9: -- MPL_DB lb <= f(x) <= ub Inequality lb <= f(x) <= ub alpar@9: -- MPL_FX f(x) = lb Equality f(x) = lb alpar@9: -- alpar@9: -- where f(x) is the corresponding linear form of the i-th row. alpar@9: -- alpar@9: -- If the row has no lower bound, *lb is set to zero; if the row has alpar@9: -- no upper bound, *ub is set to zero; and if the row is of fixed type, alpar@9: -- both *lb and *ub are set to the same value. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine returns the type of the i-th row as it is stated in the alpar@9: -- table above. */ alpar@9: alpar@9: int mpl_get_row_bnds(MPL *mpl, int i, double *_lb, double *_ub) alpar@9: { ELEMCON *con; alpar@9: int type; alpar@9: double lb, ub; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_row_bnds: invalid call sequence\n"); alpar@9: if (!(1 <= i && i <= mpl->m)) alpar@9: xfault("mpl_get_row_bnds: i = %d; row number out of range\n", alpar@9: i); alpar@9: con = mpl->row[i]; alpar@9: #if 0 /* 21/VII-2006 */ alpar@9: if (con->con->lbnd == NULL && con->con->ubnd == NULL) alpar@9: type = MPL_FR, lb = ub = 0.0; alpar@9: else if (con->con->ubnd == NULL) alpar@9: type = MPL_LO, lb = con->lbnd, ub = 0.0; alpar@9: else if (con->con->lbnd == NULL) alpar@9: type = MPL_UP, lb = 0.0, ub = con->ubnd; alpar@9: else if (con->con->lbnd != con->con->ubnd) alpar@9: type = MPL_DB, lb = con->lbnd, ub = con->ubnd; alpar@9: else alpar@9: type = MPL_FX, lb = ub = con->lbnd; alpar@9: #else alpar@9: lb = (con->con->lbnd == NULL ? -DBL_MAX : con->lbnd); alpar@9: ub = (con->con->ubnd == NULL ? +DBL_MAX : con->ubnd); alpar@9: if (lb == -DBL_MAX && ub == +DBL_MAX) alpar@9: type = MPL_FR, lb = ub = 0.0; alpar@9: else if (ub == +DBL_MAX) alpar@9: type = MPL_LO, ub = 0.0; alpar@9: else if (lb == -DBL_MAX) alpar@9: type = MPL_UP, lb = 0.0; alpar@9: else if (con->con->lbnd != con->con->ubnd) alpar@9: type = MPL_DB; alpar@9: else alpar@9: type = MPL_FX; alpar@9: #endif alpar@9: if (_lb != NULL) *_lb = lb; alpar@9: if (_ub != NULL) *_ub = ub; alpar@9: return type; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_mat_row - obtain row of the constraint matrix. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_get_mat_row stores column indices and numeric values alpar@9: -- of constraint coefficients for the i-th row to locations ndx[1], ..., alpar@9: -- ndx[len] and val[1], ..., val[len], respectively, where 0 <= len <= n alpar@9: -- is number of (structural) non-zero constraint coefficients, and n is alpar@9: -- number of columns in the problem. alpar@9: -- alpar@9: -- If the parameter ndx is NULL, column indices are not stored. If the alpar@9: -- parameter val is NULL, numeric values are not stored. alpar@9: -- alpar@9: -- Note that free rows may have constant terms, which are not part of alpar@9: -- the constraint matrix and therefore not reported by this routine. The alpar@9: -- constant term of a particular row can be obtained, if necessary, via alpar@9: -- the routine mpl_get_row_c0. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_mat_row returns len, which is length of i-th row alpar@9: -- of the constraint matrix (i.e. number of non-zero coefficients). */ alpar@9: alpar@9: int mpl_get_mat_row(MPL *mpl, int i, int ndx[], double val[]) alpar@9: { FORMULA *term; alpar@9: int len = 0; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_mat_row: invalid call sequence\n"); alpar@9: if (!(1 <= i && i <= mpl->m)) alpar@9: xfault("mpl_get_mat_row: i = %d; row number out of range\n", alpar@9: i); alpar@9: for (term = mpl->row[i]->form; term != NULL; term = term->next) alpar@9: { xassert(term->var != NULL); alpar@9: len++; alpar@9: xassert(len <= mpl->n); alpar@9: if (ndx != NULL) ndx[len] = term->var->j; alpar@9: if (val != NULL) val[len] = term->coef; alpar@9: } alpar@9: return len; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_row_c0 - obtain constant term of free row. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- double mpl_get_row_c0(MPL *mpl, int i); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_row_c0 returns numeric value of constant term of alpar@9: -- i-th row. alpar@9: -- alpar@9: -- Note that only free rows may have non-zero constant terms. Therefore alpar@9: -- if i-th row is not free, the routine returns zero. */ alpar@9: alpar@9: double mpl_get_row_c0(MPL *mpl, int i) alpar@9: { ELEMCON *con; alpar@9: double c0; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_row_c0: invalid call sequence\n"); alpar@9: if (!(1 <= i && i <= mpl->m)) alpar@9: xfault("mpl_get_row_c0: i = %d; row number out of range\n", alpar@9: i); alpar@9: con = mpl->row[i]; alpar@9: if (con->con->lbnd == NULL && con->con->ubnd == NULL) alpar@9: c0 = - con->lbnd; alpar@9: else alpar@9: c0 = 0.0; alpar@9: return c0; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_col_name - obtain column name. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- char *mpl_get_col_name(MPL *mpl, int j); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_col_name returns a pointer to internal buffer, alpar@9: -- which contains symbolic name of j-th column of the problem. */ alpar@9: alpar@9: char *mpl_get_col_name(MPL *mpl, int j) alpar@9: { char *name = mpl->mpl_buf, *t; alpar@9: int len; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_col_name: invalid call sequence\n"); alpar@9: if (!(1 <= j && j <= mpl->n)) alpar@9: xfault("mpl_get_col_name: j = %d; column number out of range\n" alpar@9: , j); alpar@9: strcpy(name, mpl->col[j]->var->name); alpar@9: len = strlen(name); alpar@9: xassert(len <= 255); alpar@9: t = format_tuple(mpl, '[', mpl->col[j]->memb->tuple); alpar@9: while (*t) alpar@9: { if (len == 255) break; alpar@9: name[len++] = *t++; alpar@9: } alpar@9: name[len] = '\0'; alpar@9: if (len == 255) strcpy(name+252, "..."); alpar@9: xassert(strlen(name) <= 255); alpar@9: return name; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_col_kind - determine column kind. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_col_kind(MPL *mpl, int j); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_get_col_kind returns the kind of j-th column, which alpar@9: -- can be one of the following: alpar@9: -- alpar@9: -- MPL_NUM - continuous variable; alpar@9: -- MPL_INT - integer variable; alpar@9: -- MPL_BIN - binary variable. alpar@9: -- alpar@9: -- Note that column kinds are defined independently on type and bounds alpar@9: -- (reported by the routine mpl_get_col_bnds) of corresponding columns. alpar@9: -- This means, in particular, that bounds of an integer column may be alpar@9: -- fractional, or a binary column may have lower and upper bounds that alpar@9: -- are not 0 and 1 (or it may have no lower/upper bound at all). */ alpar@9: alpar@9: int mpl_get_col_kind(MPL *mpl, int j) alpar@9: { int kind; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_col_kind: invalid call sequence\n"); alpar@9: if (!(1 <= j && j <= mpl->n)) alpar@9: xfault("mpl_get_col_kind: j = %d; column number out of range\n" alpar@9: , j); alpar@9: switch (mpl->col[j]->var->type) alpar@9: { case A_NUMERIC: alpar@9: kind = MPL_NUM; break; alpar@9: case A_INTEGER: alpar@9: kind = MPL_INT; break; alpar@9: case A_BINARY: alpar@9: kind = MPL_BIN; break; alpar@9: default: alpar@9: xassert(mpl != mpl); alpar@9: } alpar@9: return kind; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_get_col_bnds - obtain column bounds. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_get_col_bnds(MPL *mpl, int j, double *lb, double *ub); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_get_col_bnds stores lower and upper bound of j-th alpar@9: -- column of the problem to the locations, which the parameters lb and alpar@9: -- ub point to, respectively. Besides the routine returns the type of alpar@9: -- the j-th column. alpar@9: -- alpar@9: -- If some of the parameters lb and ub is NULL, the corresponding bound alpar@9: -- value is not stored. alpar@9: -- alpar@9: -- Types and bounds have the following meaning: alpar@9: -- alpar@9: -- Type Bounds Note alpar@9: -- ------------------------------------------------------ alpar@9: -- MPL_FR -inf < x < +inf Free (unbounded) variable alpar@9: -- MPL_LO lb <= x < +inf Variable with lower bound alpar@9: -- MPL_UP -inf < x <= ub Variable with upper bound alpar@9: -- MPL_DB lb <= x <= ub Double-bounded variable alpar@9: -- MPL_FX x = lb Fixed variable alpar@9: -- alpar@9: -- where x is individual variable corresponding to the j-th column. alpar@9: -- alpar@9: -- If the column has no lower bound, *lb is set to zero; if the column alpar@9: -- has no upper bound, *ub is set to zero; and if the column is of fixed alpar@9: -- type, both *lb and *ub are set to the same value. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine returns the type of the j-th column as it is stated in alpar@9: -- the table above. */ alpar@9: alpar@9: int mpl_get_col_bnds(MPL *mpl, int j, double *_lb, double *_ub) alpar@9: { ELEMVAR *var; alpar@9: int type; alpar@9: double lb, ub; alpar@9: if (mpl->phase != 3) alpar@9: xfault("mpl_get_col_bnds: invalid call sequence\n"); alpar@9: if (!(1 <= j && j <= mpl->n)) alpar@9: xfault("mpl_get_col_bnds: j = %d; column number out of range\n" alpar@9: , j); alpar@9: var = mpl->col[j]; alpar@9: #if 0 /* 21/VII-2006 */ alpar@9: if (var->var->lbnd == NULL && var->var->ubnd == NULL) alpar@9: type = MPL_FR, lb = ub = 0.0; alpar@9: else if (var->var->ubnd == NULL) alpar@9: type = MPL_LO, lb = var->lbnd, ub = 0.0; alpar@9: else if (var->var->lbnd == NULL) alpar@9: type = MPL_UP, lb = 0.0, ub = var->ubnd; alpar@9: else if (var->var->lbnd != var->var->ubnd) alpar@9: type = MPL_DB, lb = var->lbnd, ub = var->ubnd; alpar@9: else alpar@9: type = MPL_FX, lb = ub = var->lbnd; alpar@9: #else alpar@9: lb = (var->var->lbnd == NULL ? -DBL_MAX : var->lbnd); alpar@9: ub = (var->var->ubnd == NULL ? +DBL_MAX : var->ubnd); alpar@9: if (lb == -DBL_MAX && ub == +DBL_MAX) alpar@9: type = MPL_FR, lb = ub = 0.0; alpar@9: else if (ub == +DBL_MAX) alpar@9: type = MPL_LO, ub = 0.0; alpar@9: else if (lb == -DBL_MAX) alpar@9: type = MPL_UP, lb = 0.0; alpar@9: else if (var->var->lbnd != var->var->ubnd) alpar@9: type = MPL_DB; alpar@9: else alpar@9: type = MPL_FX; alpar@9: #endif alpar@9: if (_lb != NULL) *_lb = lb; alpar@9: if (_ub != NULL) *_ub = ub; alpar@9: return type; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_has_solve_stmt - check if model has solve statement. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_has_solve_stmt(MPL *mpl); alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- If the model has the solve statement, the routine returns non-zero, alpar@9: -- otherwise zero is returned. */ alpar@9: alpar@9: int mpl_has_solve_stmt(MPL *mpl) alpar@9: { if (mpl->phase != 3) alpar@9: xfault("mpl_has_solve_stmt: invalid call sequence\n"); alpar@9: return mpl->flag_s; alpar@9: } alpar@9: alpar@9: #if 1 /* 15/V-2010 */ alpar@9: void mpl_put_row_soln(MPL *mpl, int i, int stat, double prim, alpar@9: double dual) alpar@9: { /* store row (constraint/objective) solution components */ alpar@9: xassert(mpl->phase == 3); alpar@9: xassert(1 <= i && i <= mpl->m); alpar@9: mpl->row[i]->stat = stat; alpar@9: mpl->row[i]->prim = prim; alpar@9: mpl->row[i]->dual = dual; alpar@9: return; alpar@9: } alpar@9: #endif alpar@9: alpar@9: #if 1 /* 15/V-2010 */ alpar@9: void mpl_put_col_soln(MPL *mpl, int j, int stat, double prim, alpar@9: double dual) alpar@9: { /* store column (variable) solution components */ alpar@9: xassert(mpl->phase == 3); alpar@9: xassert(1 <= j && j <= mpl->n); alpar@9: mpl->col[j]->stat = stat; alpar@9: mpl->col[j]->prim = prim; alpar@9: mpl->col[j]->dual = dual; alpar@9: return; alpar@9: } alpar@9: #endif alpar@9: alpar@9: #if 0 /* 15/V-2010 */ alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_put_col_value - store column value. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- void mpl_put_col_value(MPL *mpl, int j, double val); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_put_col_value stores numeric value of j-th column alpar@9: -- into the translator database. It is assumed that the column value is alpar@9: -- provided by the solver. */ alpar@9: alpar@9: void mpl_put_col_value(MPL *mpl, int j, double val) alpar@9: { if (mpl->phase != 3) alpar@9: xfault("mpl_put_col_value: invalid call sequence\n"); alpar@9: if (!(1 <= j && j <= mpl->n)) alpar@9: xfault( alpar@9: "mpl_put_col_value: j = %d; column number out of range\n", j); alpar@9: mpl->col[j]->prim = val; alpar@9: return; alpar@9: } alpar@9: #endif alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_postsolve - postsolve model. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- int mpl_postsolve(MPL *mpl); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_postsolve performs postsolving of the model using alpar@9: -- its description stored in the translator database. This phase means alpar@9: -- executing statements, which follow the solve statement. alpar@9: -- alpar@9: -- If this routine is used, it should be called once after the routine alpar@9: -- mpl_generate and if the latter returned the code 3. alpar@9: -- alpar@9: -- *Returns* alpar@9: -- alpar@9: -- The routine mpl_postsolve returns one of the following codes: alpar@9: -- alpar@9: -- 3 - model has been successfully postsolved. alpar@9: -- 4 - processing failed due to some errors. In this case the calling alpar@9: -- program should call the routine mpl_terminate to terminate model alpar@9: -- processing. */ alpar@9: alpar@9: int mpl_postsolve(MPL *mpl) alpar@9: { if (!(mpl->phase == 3 && !mpl->flag_p)) alpar@9: xfault("mpl_postsolve: invalid call sequence\n"); alpar@9: /* set up error handler */ alpar@9: if (setjmp(mpl->jump)) goto done; alpar@9: /* perform postsolving */ alpar@9: postsolve_model(mpl); alpar@9: flush_output(mpl); alpar@9: /* postsolving phase has been finished */ alpar@9: xprintf("Model has been successfully processed\n"); alpar@9: done: /* return to the calling program */ alpar@9: return mpl->phase; alpar@9: } alpar@9: alpar@9: /*---------------------------------------------------------------------- alpar@9: -- mpl_terminate - free all resources used by translator. alpar@9: -- alpar@9: -- *Synopsis* alpar@9: -- alpar@9: -- #include "glpmpl.h" alpar@9: -- void mpl_terminate(MPL *mpl); alpar@9: -- alpar@9: -- *Description* alpar@9: -- alpar@9: -- The routine mpl_terminate frees all the resources used by the GNU alpar@9: -- MathProg translator. */ alpar@9: alpar@9: void mpl_terminate(MPL *mpl) alpar@9: { if (setjmp(mpl->jump)) xassert(mpl != mpl); alpar@9: switch (mpl->phase) alpar@9: { case 0: alpar@9: case 1: alpar@9: case 2: alpar@9: case 3: alpar@9: /* there were no errors; clean the model content */ alpar@9: clean_model(mpl); alpar@9: xassert(mpl->a_list == NULL); alpar@9: #if 1 /* 11/II-2008 */ alpar@9: xassert(mpl->dca == NULL); alpar@9: #endif alpar@9: break; alpar@9: case 4: alpar@9: /* model processing has been finished due to error; delete alpar@9: search trees, which may be created for some arrays */ alpar@9: { ARRAY *a; alpar@9: for (a = mpl->a_list; a != NULL; a = a->next) alpar@9: if (a->tree != NULL) avl_delete_tree(a->tree); alpar@9: } alpar@9: #if 1 /* 11/II-2008 */ alpar@9: free_dca(mpl); alpar@9: #endif alpar@9: break; alpar@9: default: alpar@9: xassert(mpl != mpl); alpar@9: } alpar@9: /* delete the translator database */ alpar@9: xfree(mpl->image); alpar@9: xfree(mpl->b_image); alpar@9: xfree(mpl->f_image); alpar@9: xfree(mpl->context); alpar@9: dmp_delete_pool(mpl->pool); alpar@9: avl_delete_tree(mpl->tree); alpar@9: dmp_delete_pool(mpl->strings); alpar@9: dmp_delete_pool(mpl->symbols); alpar@9: dmp_delete_pool(mpl->tuples); alpar@9: dmp_delete_pool(mpl->arrays); alpar@9: dmp_delete_pool(mpl->members); alpar@9: dmp_delete_pool(mpl->elemvars); alpar@9: dmp_delete_pool(mpl->formulae); alpar@9: dmp_delete_pool(mpl->elemcons); alpar@9: xfree(mpl->sym_buf); alpar@9: xfree(mpl->tup_buf); alpar@9: rng_delete_rand(mpl->rand); alpar@9: if (mpl->row != NULL) xfree(mpl->row); alpar@9: if (mpl->col != NULL) xfree(mpl->col); alpar@9: if (mpl->in_fp != NULL) xfclose(mpl->in_fp); alpar@9: if (mpl->out_fp != NULL && mpl->out_fp != (void *)stdout) alpar@9: xfclose(mpl->out_fp); alpar@9: if (mpl->out_file != NULL) xfree(mpl->out_file); alpar@9: if (mpl->prt_fp != NULL) xfclose(mpl->prt_fp); alpar@9: if (mpl->prt_file != NULL) xfree(mpl->prt_file); alpar@9: if (mpl->mod_file != NULL) xfree(mpl->mod_file); alpar@9: xfree(mpl->mpl_buf); alpar@9: xfree(mpl); alpar@9: return; alpar@9: } alpar@9: alpar@9: /* eof */