diff options
author | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 |
---|---|---|
committer | Pasha <pasha@member.fsf.org> | 2023-01-27 00:54:07 +0000 |
commit | ef800d4ffafdbde7d7a172ad73bd984b1695c138 (patch) | |
tree | 920cc189130f1e98f252283fce94851443641a6d /glpk-5.0/src/api | |
parent | ec4ae3c2b5cb0e83fb667f14f832ea94f68ef075 (diff) | |
download | oneapi-ef800d4ffafdbde7d7a172ad73bd984b1695c138.tar.gz oneapi-ef800d4ffafdbde7d7a172ad73bd984b1695c138.tar.bz2 |
Diffstat (limited to 'glpk-5.0/src/api')
55 files changed, 13138 insertions, 0 deletions
diff --git a/glpk-5.0/src/api/advbas.c b/glpk-5.0/src/api/advbas.c new file mode 100644 index 0000000..1aa76d0 --- /dev/null +++ b/glpk-5.0/src/api/advbas.c @@ -0,0 +1,153 @@ +/* advbas.c (construct advanced initial LP basis) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2008-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" +#include "triang.h" + +/*********************************************************************** +* NAME +* +* glp_adv_basis - construct advanced initial LP basis +* +* SYNOPSIS +* +* void glp_adv_basis(glp_prob *P, int flags); +* +* DESCRIPTION +* +* The routine glp_adv_basis constructs an advanced initial LP basis +* for the specified problem object. +* +* The parameter flag is reserved for use in the future and should be +* specified as zero. +* +* NOTE +* +* The routine glp_adv_basis should be called after the constraint +* matrix has been scaled (if scaling is used). */ + +static int mat(void *info, int k, int ind[], double val[]) +{ glp_prob *P = info; + int m = P->m; + int n = P->n; + GLPROW **row = P->row; + GLPCOL **col = P->col; + GLPAIJ *aij; + int i, j, len; + if (k > 0) + { /* retrieve scaled row of constraint matrix */ + i = +k; + xassert(1 <= i && i <= m); + len = 0; + if (row[i]->type == GLP_FX) + { for (aij = row[i]->ptr; aij != NULL; aij = aij->r_next) + { j = aij->col->j; + if (col[j]->type != GLP_FX) + { len++; + ind[len] = j; + val[len] = aij->row->rii * aij->val * aij->col->sjj; + } + } + } + } + else + { /* retrieve scaled column of constraint matrix */ + j = -k; + xassert(1 <= j && j <= n); + len = 0; + if (col[j]->type != GLP_FX) + { for (aij = col[j]->ptr; aij != NULL; aij = aij->c_next) + { i = aij->row->i; + if (row[i]->type == GLP_FX) + { len++; + ind[len] = i; + val[len] = aij->row->rii * aij->val * aij->col->sjj; + } + } + } + } + return len; +} + +void glp_adv_basis(glp_prob *P, int flags) +{ int i, j, k, m, n, min_mn, size, *rn, *cn; + char *flag; + if (flags != 0) + xerror("glp_adv_basis: flags = %d; invalid flags\n", flags); + m = P->m; /* number of rows */ + n = P->n; /* number of columns */ + if (m == 0 || n == 0) + { /* trivial case */ + glp_std_basis(P); + goto done; + } + xprintf("Constructing initial basis...\n"); + /* allocate working arrays */ + min_mn = (m < n ? m : n); + rn = talloc(1+min_mn, int); + cn = talloc(1+min_mn, int); + flag = talloc(1+m, char); + /* make the basis empty */ + for (i = 1; i <= m; i++) + { flag[i] = 0; + glp_set_row_stat(P, i, GLP_NS); + } + for (j = 1; j <= n; j++) + glp_set_col_stat(P, j, GLP_NS); + /* find maximal triangular part of the constraint matrix; + to prevent including non-fixed rows and fixed columns in the + triangular part, such rows and columns are temporarily made + empty by the routine mat */ +#if 1 /* FIXME: tolerance */ + size = triang(m, n, mat, P, 0.001, rn, cn); +#endif + xassert(0 <= size && size <= min_mn); + /* include in the basis non-fixed structural variables, whose + columns constitute the triangular part */ + for (k = 1; k <= size; k++) + { i = rn[k]; + xassert(1 <= i && i <= m); + flag[i] = 1; + j = cn[k]; + xassert(1 <= j && j <= n); + glp_set_col_stat(P, j, GLP_BS); + } + /* include in the basis appropriate auxiliary variables, whose + unity columns preserve triangular form of the basis matrix */ + for (i = 1; i <= m; i++) + { if (flag[i] == 0) + { glp_set_row_stat(P, i, GLP_BS); + if (P->row[i]->type != GLP_FX) + size++; + } + } + /* size of triangular part = (number of rows) - (number of basic + fixed auxiliary variables) */ + xprintf("Size of triangular part is %d\n", size); + /* deallocate working arrays */ + tfree(rn); + tfree(cn); + tfree(flag); +done: return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnhall.c b/glpk-5.0/src/api/asnhall.c new file mode 100644 index 0000000..38ac287 --- /dev/null +++ b/glpk-5.0/src/api/asnhall.c @@ -0,0 +1,161 @@ +/* asnhall.c (find bipartite matching of maximum cardinality) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "mc21a.h" + +/*********************************************************************** +* NAME +* +* glp_asnprob_hall - find bipartite matching of maximum cardinality +* +* SYNOPSIS +* +* int glp_asnprob_hall(glp_graph *G, int v_set, int a_x); +* +* DESCRIPTION +* +* The routine glp_asnprob_hall finds a matching of maximal cardinality +* in the specified bipartite graph G. It uses a version of the Fortran +* routine MC21A developed by I.S.Duff [1], which implements Hall's +* algorithm [2]. +* +* RETURNS +* +* The routine glp_asnprob_hall returns the cardinality of the matching +* found. However, if the specified graph is incorrect (as detected by +* the routine glp_check_asnprob), the routine returns negative value. +* +* REFERENCES +* +* 1. I.S.Duff, Algorithm 575: Permutations for zero-free diagonal, ACM +* Trans. on Math. Softw. 7 (1981), 387-390. +* +* 2. M.Hall, "An Algorithm for distinct representatives," Amer. Math. +* Monthly 63 (1956), 716-717. */ + +int glp_asnprob_hall(glp_graph *G, int v_set, int a_x) +{ glp_vertex *v; + glp_arc *a; + int card, i, k, loc, n, n1, n2, xij; + int *num, *icn, *ip, *lenr, *iperm, *pr, *arp, *cv, *out; + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_asnprob_hall: v_set = %d; invalid offset\n", + v_set); + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) + xerror("glp_asnprob_hall: a_x = %d; invalid offset\n", a_x); + if (glp_check_asnprob(G, v_set)) + return -1; + /* determine the number of vertices in sets R and S and renumber + vertices in S which correspond to columns of the matrix; skip + all isolated vertices */ + num = xcalloc(1+G->nv, sizeof(int)); + n1 = n2 = 0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (v->in == NULL && v->out != NULL) + n1++, num[i] = 0; /* vertex in R */ + else if (v->in != NULL && v->out == NULL) + n2++, num[i] = n2; /* vertex in S */ + else + { xassert(v->in == NULL && v->out == NULL); + num[i] = -1; /* isolated vertex */ + } + } + /* the matrix must be square, thus, if it has more columns than + rows, extra rows will be just empty, and vice versa */ + n = (n1 >= n2 ? n1 : n2); + /* allocate working arrays */ + icn = xcalloc(1+G->na, sizeof(int)); + ip = xcalloc(1+n, sizeof(int)); + lenr = xcalloc(1+n, sizeof(int)); + iperm = xcalloc(1+n, sizeof(int)); + pr = xcalloc(1+n, sizeof(int)); + arp = xcalloc(1+n, sizeof(int)); + cv = xcalloc(1+n, sizeof(int)); + out = xcalloc(1+n, sizeof(int)); + /* build the adjacency matrix of the bipartite graph in row-wise + format (rows are vertices in R, columns are vertices in S) */ + k = 0, loc = 1; + for (i = 1; i <= G->nv; i++) + { if (num[i] != 0) continue; + /* vertex i in R */ + ip[++k] = loc; + v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { xassert(num[a->head->i] != 0); + icn[loc++] = num[a->head->i]; + } + lenr[k] = loc - ip[k]; + } + xassert(loc-1 == G->na); + /* make all extra rows empty (all extra columns are empty due to + the row-wise format used) */ + for (k++; k <= n; k++) + ip[k] = loc, lenr[k] = 0; + /* find a row permutation that maximizes the number of non-zeros + on the main diagonal */ + card = mc21a(n, icn, ip, lenr, iperm, pr, arp, cv, out); +#if 1 /* 18/II-2010 */ + /* FIXED: if card = n, arp remains clobbered on exit */ + for (i = 1; i <= n; i++) + arp[i] = 0; + for (i = 1; i <= card; i++) + { k = iperm[i]; + xassert(1 <= k && k <= n); + xassert(arp[k] == 0); + arp[k] = i; + } +#endif + /* store solution, if necessary */ + if (a_x < 0) goto skip; + k = 0; + for (i = 1; i <= G->nv; i++) + { if (num[i] != 0) continue; + /* vertex i in R */ + k++; + v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { /* arp[k] is the number of matched column or zero */ + if (arp[k] == num[a->head->i]) + { xassert(arp[k] != 0); + xij = 1; + } + else + xij = 0; + memcpy((char *)a->data + a_x, &xij, sizeof(int)); + } + } +skip: /* free working arrays */ + xfree(num); + xfree(icn); + xfree(ip); + xfree(lenr); + xfree(iperm); + xfree(pr); + xfree(arp); + xfree(cv); + xfree(out); + return card; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnlp.c b/glpk-5.0/src/api/asnlp.c new file mode 100644 index 0000000..b7bac6c --- /dev/null +++ b/glpk-5.0/src/api/asnlp.c @@ -0,0 +1,102 @@ +/* asnlp.c (convert assignment problem to LP) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_asnprob_lp - convert assignment problem to LP +* +* SYNOPSIS +* +* int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, +* int v_set, int a_cost); +* +* DESCRIPTION +* +* The routine glp_asnprob_lp builds an LP problem, which corresponds +* to the assignment problem on the specified graph G. +* +* RETURNS +* +* If the LP problem has been successfully built, the routine returns +* zero, otherwise, non-zero. */ + +int glp_asnprob_lp(glp_prob *P, int form, glp_graph *G, int names, + int v_set, int a_cost) +{ glp_vertex *v; + glp_arc *a; + int i, j, ret, ind[1+2]; + double cost, val[1+2]; + if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || + form == GLP_ASN_MMP)) + xerror("glp_asnprob_lp: form = %d; invalid parameter\n", + form); + if (!(names == GLP_ON || names == GLP_OFF)) + xerror("glp_asnprob_lp: names = %d; invalid parameter\n", + names); + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_asnprob_lp: v_set = %d; invalid offset\n", + v_set); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_asnprob_lp: a_cost = %d; invalid offset\n", + a_cost); + ret = glp_check_asnprob(G, v_set); + if (ret != 0) goto done; + glp_erase_prob(P); + if (names) glp_set_prob_name(P, G->name); + glp_set_obj_dir(P, form == GLP_ASN_MIN ? GLP_MIN : GLP_MAX); + if (G->nv > 0) glp_add_rows(P, G->nv); + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (names) glp_set_row_name(P, i, v->name); + glp_set_row_bnds(P, i, form == GLP_ASN_MMP ? GLP_UP : GLP_FX, + 1.0, 1.0); + } + if (G->na > 0) glp_add_cols(P, G->na); + for (i = 1, j = 0; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { j++; + if (names) + { char name[50+1]; + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); + xassert(strlen(name) < sizeof(name)); + glp_set_col_name(P, j, name); + } + ind[1] = a->tail->i, val[1] = +1.0; + ind[2] = a->head->i, val[2] = +1.0; + glp_set_mat_col(P, j, 2, ind, val); + glp_set_col_bnds(P, j, GLP_DB, 0.0, 1.0); + if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 1.0; + glp_set_obj_coef(P, j, cost); + } + } + xassert(j == G->na); +done: return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/asnokalg.c b/glpk-5.0/src/api/asnokalg.c new file mode 100644 index 0000000..54236e7 --- /dev/null +++ b/glpk-5.0/src/api/asnokalg.c @@ -0,0 +1,152 @@ +/* asnokalg.c (solve assignment problem with out-of-kilter alg.) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "okalg.h" + +int glp_asnprob_okalg(int form, glp_graph *G, int v_set, int a_cost, + double *sol, int a_x) +{ /* solve assignment problem with out-of-kilter algorithm */ + glp_vertex *v; + glp_arc *a; + int nv, na, i, k, *tail, *head, *low, *cap, *cost, *x, *pi, ret; + double temp; + if (!(form == GLP_ASN_MIN || form == GLP_ASN_MAX || + form == GLP_ASN_MMP)) + xerror("glp_asnprob_okalg: form = %d; invalid parameter\n", + form); + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_asnprob_okalg: v_set = %d; invalid offset\n", + v_set); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_asnprob_okalg: a_cost = %d; invalid offset\n", + a_cost); + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(int)) + xerror("glp_asnprob_okalg: a_x = %d; invalid offset\n", a_x); + if (glp_check_asnprob(G, v_set)) + return GLP_EDATA; + /* nv is the total number of nodes in the resulting network */ + nv = G->nv + 1; + /* na is the total number of arcs in the resulting network */ + na = G->na + G->nv; + /* allocate working arrays */ + tail = xcalloc(1+na, sizeof(int)); + head = xcalloc(1+na, sizeof(int)); + low = xcalloc(1+na, sizeof(int)); + cap = xcalloc(1+na, sizeof(int)); + cost = xcalloc(1+na, sizeof(int)); + x = xcalloc(1+na, sizeof(int)); + pi = xcalloc(1+nv, sizeof(int)); + /* construct the resulting network */ + k = 0; + /* (original arcs) */ + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + tail[k] = a->tail->i; + head[k] = a->head->i; + low[k] = 0; + cap[k] = 1; + if (a_cost >= 0) + memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); + else + temp = 1.0; + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + cost[k] = (int)temp; + if (form != GLP_ASN_MIN) cost[k] = - cost[k]; + } + } + /* (artificial arcs) */ + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + k++; + if (v->out == NULL) + tail[k] = i, head[k] = nv; + else if (v->in == NULL) + tail[k] = nv, head[k] = i; + else + xassert(v != v); + low[k] = (form == GLP_ASN_MMP ? 0 : 1); + cap[k] = 1; + cost[k] = 0; + } + xassert(k == na); + /* find minimal-cost circulation in the resulting network */ + ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); + switch (ret) + { case 0: + /* optimal circulation found */ + ret = 0; + break; + case 1: + /* no feasible circulation exists */ + ret = GLP_ENOPFS; + break; + case 2: + /* integer overflow occured */ + ret = GLP_ERANGE; + goto done; + case 3: + /* optimality test failed (logic error) */ + ret = GLP_EFAIL; + goto done; + default: + xassert(ret != ret); + } + /* store solution components */ + /* (objective function = the total cost) */ + if (sol != NULL) + { temp = 0.0; + for (k = 1; k <= na; k++) + temp += (double)cost[k] * (double)x[k]; + if (form != GLP_ASN_MIN) temp = - temp; + *sol = temp; + } + /* (arc flows) */ + if (a_x >= 0) + { k = 0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + if (ret == 0) + xassert(x[k] == 0 || x[k] == 1); + memcpy((char *)a->data + a_x, &x[k], sizeof(int)); + } + } + } +done: /* free working arrays */ + xfree(tail); + xfree(head); + xfree(low); + xfree(cap); + xfree(cost); + xfree(x); + xfree(pi); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/ckasn.c b/glpk-5.0/src/api/ckasn.c new file mode 100644 index 0000000..0cb9e0d --- /dev/null +++ b/glpk-5.0/src/api/ckasn.c @@ -0,0 +1,76 @@ +/* ckasn.c (check correctness of assignment problem data) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_check_asnprob - check correctness of assignment problem data +* +* SYNOPSIS +* +* int glp_check_asnprob(glp_graph *G, int v_set); +* +* RETURNS +* +* If the specified assignment problem data are correct, the routine +* glp_check_asnprob returns zero, otherwise, non-zero. */ + +int glp_check_asnprob(glp_graph *G, int v_set) +{ glp_vertex *v; + int i, k, ret = 0; + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_check_asnprob: v_set = %d; invalid offset\n", + v_set); + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (v_set >= 0) + { memcpy(&k, (char *)v->data + v_set, sizeof(int)); + if (k == 0) + { if (v->in != NULL) + { ret = 1; + break; + } + } + else if (k == 1) + { if (v->out != NULL) + { ret = 2; + break; + } + } + else + { ret = 3; + break; + } + } + else + { if (v->in != NULL && v->out != NULL) + { ret = 4; + break; + } + } + } + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/ckcnf.c b/glpk-5.0/src/api/ckcnf.c new file mode 100644 index 0000000..26decce --- /dev/null +++ b/glpk-5.0/src/api/ckcnf.c @@ -0,0 +1,80 @@ +/* ckcnf.c (check for CNF-SAT problem instance) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +int glp_check_cnfsat(glp_prob *P) +{ /* check for CNF-SAT problem instance */ + int m = P->m; + int n = P->n; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij; + int i, j, neg; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_check_cnfsat: P = %p; invalid problem object\n", + P); +#endif + /* check columns */ + for (j = 1; j <= n; j++) + { col = P->col[j]; + /* the variable should be binary */ + if (!(col->kind == GLP_IV && col->type == GLP_DB && + col->lb == 0.0 && col->ub == 1.0)) + return 1; + } + /* objective function should be zero */ + if (P->c0 != 0.0) + return 2; + for (j = 1; j <= n; j++) + { col = P->col[j]; + if (col->coef != 0.0) + return 3; + } + /* check rows */ + for (i = 1; i <= m; i++) + { row = P->row[i]; + /* the row should be of ">=" type */ + if (row->type != GLP_LO) + return 4; + /* check constraint coefficients */ + neg = 0; + for (aij = row->ptr; aij != NULL; aij = aij->r_next) + { /* the constraint coefficient should be +1 or -1 */ + if (aij->val == +1.0) + ; + else if (aij->val == -1.0) + neg++; + else + return 5; + } + /* the right-hand side should be (1 - neg), where neg is the + number of negative constraint coefficients in the row */ + if (row->lb != (double)(1 - neg)) + return 6; + } + /* congratulations; this is CNF-SAT */ + return 0; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cplex.c b/glpk-5.0/src/api/cplex.c new file mode 100644 index 0000000..45ecaa2 --- /dev/null +++ b/glpk-5.0/src/api/cplex.c @@ -0,0 +1,1281 @@ +/* cplex.c (CPLEX LP format routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2018 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_init_cpxcp - initialize CPLEX LP format control parameters +* +* SYNOPSIS +* +* void glp_init_cpxcp(glp_cpxcp *parm): +* +* The routine glp_init_cpxcp initializes control parameters used by +* the CPLEX LP input/output routines glp_read_lp and glp_write_lp with +* default values. +* +* Default values of the control parameters are stored in the glp_cpxcp +* structure, which the parameter parm points to. */ + +void glp_init_cpxcp(glp_cpxcp *parm) +{ xassert(parm != NULL); + return; +} + +static void check_parm(const char *func, const glp_cpxcp *parm) +{ /* check control parameters */ + xassert(func != NULL); + xassert(parm != NULL); + return; +} + +/*********************************************************************** +* NAME +* +* glp_read_lp - read problem data in CPLEX LP format +* +* SYNOPSIS +* +* int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char +* *fname); +* +* DESCRIPTION +* +* The routine glp_read_lp reads problem data in CPLEX LP format from +* a text file. +* +* The parameter parm is a pointer to the structure glp_cpxcp, which +* specifies control parameters used by the routine. If parm is NULL, +* the routine uses default settings. +* +* The character string fname specifies a name of the text file to be +* read. +* +* Note that before reading data the current content of the problem +* object is completely erased with the routine glp_erase_prob. +* +* RETURNS +* +* If the operation was successful, the routine glp_read_lp returns +* zero. Otherwise, it prints an error message and returns non-zero. */ + +struct csa +{ /* common storage area */ + glp_prob *P; + /* LP/MIP problem object */ + const glp_cpxcp *parm; + /* pointer to control parameters */ + const char *fname; + /* name of input CPLEX LP file */ + glp_file *fp; + /* stream assigned to input CPLEX LP file */ + jmp_buf jump; + /* label for go to in case of error */ + int count; + /* line count */ + int c; + /* current character or EOF */ + int token; + /* current token: */ +#define T_EOF 0x00 /* end of file */ +#define T_MINIMIZE 0x01 /* keyword 'minimize' */ +#define T_MAXIMIZE 0x02 /* keyword 'maximize' */ +#define T_SUBJECT_TO 0x03 /* keyword 'subject to' */ +#define T_BOUNDS 0x04 /* keyword 'bounds' */ +#define T_GENERAL 0x05 /* keyword 'general' */ +#define T_INTEGER 0x06 /* keyword 'integer' */ +#define T_BINARY 0x07 /* keyword 'binary' */ +#define T_END 0x08 /* keyword 'end' */ +#define T_NAME 0x09 /* symbolic name */ +#define T_NUMBER 0x0A /* numeric constant */ +#define T_PLUS 0x0B /* delimiter '+' */ +#define T_MINUS 0x0C /* delimiter '-' */ +#define T_COLON 0x0D /* delimiter ':' */ +#define T_LE 0x0E /* delimiter '<=' */ +#define T_GE 0x0F /* delimiter '>=' */ +#define T_EQ 0x10 /* delimiter '=' */ + char image[255+1]; + /* image of current token */ + int imlen; + /* length of token image */ + double value; + /* value of numeric constant */ + int n_max; + /* length of the following five arrays (enlarged automatically, + if necessary) */ + int *ind; /* int ind[1+n_max]; */ + double *val; /* double val[1+n_max]; */ + char *flag; /* char flag[1+n_max]; */ + /* working arrays used to construct linear forms */ + double *lb; /* double lb[1+n_max]; */ + double *ub; /* double ub[1+n_max]; */ + /* lower and upper bounds of variables (columns) */ +#if 1 /* 27/VII-2013 */ + int lb_warn, ub_warn; + /* warning 'lower/upper bound redefined' already issued */ +#endif +}; + +#define CHAR_SET "!\"#$%&()/,.;?@_`'{}|~" +/* characters that may appear in symbolic names */ + +static void error(struct csa *csa, const char *fmt, ...) +{ /* print error message and terminate processing */ + va_list arg; + xprintf("%s:%d: ", csa->fname, csa->count); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + longjmp(csa->jump, 1); + /* no return */ +} + +static void warning(struct csa *csa, const char *fmt, ...) +{ /* print warning message and continue processing */ + va_list arg; + xprintf("%s:%d: warning: ", csa->fname, csa->count); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + return; +} + +static void read_char(struct csa *csa) +{ /* read next character from input file */ + int c; + xassert(csa->c != EOF); + if (csa->c == '\n') csa->count++; + c = glp_getc(csa->fp); + if (c < 0) + { if (glp_ioerr(csa->fp)) + error(csa, "read error - %s\n", get_err_msg()); + else if (csa->c == '\n') + { csa->count--; + c = EOF; + } + else + { warning(csa, "missing final end of line\n"); + c = '\n'; + } + } + else if (c == '\n') + ; + else if (isspace(c)) + c = ' '; + else if (iscntrl(c)) + error(csa, "invalid control character 0x%02X\n", c); + csa->c = c; + return; +} + +static void add_char(struct csa *csa) +{ /* append current character to current token */ + if (csa->imlen == sizeof(csa->image)-1) + error(csa, "token '%.15s...' too long\n", csa->image); + csa->image[csa->imlen++] = (char)csa->c; + csa->image[csa->imlen] = '\0'; + read_char(csa); + return; +} + +static int the_same(char *s1, char *s2) +{ /* compare two character strings ignoring case sensitivity */ + for (; *s1 != '\0'; s1++, s2++) + { if (tolower((unsigned char)*s1) != tolower((unsigned char)*s2)) + return 0; + } + return 1; +} + +static void scan_token(struct csa *csa) +{ /* scan next token */ + int flag; + csa->token = -1; + csa->image[0] = '\0'; + csa->imlen = 0; + csa->value = 0.0; +loop: flag = 0; + /* skip non-significant characters */ + while (csa->c == ' ') read_char(csa); + /* recognize and scan current token */ + if (csa->c == EOF) + csa->token = T_EOF; + else if (csa->c == '\n') + { read_char(csa); + /* if the next character is letter, it may begin a keyword */ + if (isalpha(csa->c)) + { flag = 1; + goto name; + } + goto loop; + } + else if (csa->c == '\\') + { /* comment; ignore everything until end-of-line */ + while (csa->c != '\n') read_char(csa); + goto loop; + } + else if (isalpha(csa->c) || csa->c != '.' && strchr(CHAR_SET, + csa->c) != NULL) +name: { /* symbolic name */ + csa->token = T_NAME; + while (isalnum(csa->c) || strchr(CHAR_SET, csa->c) != NULL) + add_char(csa); + if (flag) + { /* check for keyword */ + if (the_same(csa->image, "minimize")) + csa->token = T_MINIMIZE; + else if (the_same(csa->image, "minimum")) + csa->token = T_MINIMIZE; + else if (the_same(csa->image, "min")) + csa->token = T_MINIMIZE; + else if (the_same(csa->image, "maximize")) + csa->token = T_MAXIMIZE; + else if (the_same(csa->image, "maximum")) + csa->token = T_MAXIMIZE; + else if (the_same(csa->image, "max")) + csa->token = T_MAXIMIZE; + else if (the_same(csa->image, "subject")) + { if (csa->c == ' ') + { read_char(csa); + if (tolower(csa->c) == 't') + { csa->token = T_SUBJECT_TO; + csa->image[csa->imlen++] = ' '; + csa->image[csa->imlen] = '\0'; + add_char(csa); + if (tolower(csa->c) != 'o') + error(csa, "keyword 'subject to' incomplete\n"); + add_char(csa); + if (isalpha(csa->c)) + error(csa, "keyword '%s%c...' not recognized\n", + csa->image, csa->c); + } + } + } + else if (the_same(csa->image, "such")) + { if (csa->c == ' ') + { read_char(csa); + if (tolower(csa->c) == 't') + { csa->token = T_SUBJECT_TO; + csa->image[csa->imlen++] = ' '; + csa->image[csa->imlen] = '\0'; + add_char(csa); + if (tolower(csa->c) != 'h') +err: error(csa, "keyword 'such that' incomplete\n"); + add_char(csa); + if (tolower(csa->c) != 'a') goto err; + add_char(csa); + if (tolower(csa->c) != 't') goto err; + add_char(csa); + if (isalpha(csa->c)) + error(csa, "keyword '%s%c...' not recognized\n", + csa->image, csa->c); + } + } + } + else if (the_same(csa->image, "st")) + csa->token = T_SUBJECT_TO; + else if (the_same(csa->image, "s.t.")) + csa->token = T_SUBJECT_TO; + else if (the_same(csa->image, "st.")) + csa->token = T_SUBJECT_TO; + else if (the_same(csa->image, "bounds")) + csa->token = T_BOUNDS; + else if (the_same(csa->image, "bound")) + csa->token = T_BOUNDS; + else if (the_same(csa->image, "general")) + csa->token = T_GENERAL; + else if (the_same(csa->image, "generals")) + csa->token = T_GENERAL; + else if (the_same(csa->image, "gen")) + csa->token = T_GENERAL; + else if (the_same(csa->image, "integer")) + csa->token = T_INTEGER; + else if (the_same(csa->image, "integers")) + csa->token = T_INTEGER; + else if (the_same(csa->image, "int")) + csa->token = T_INTEGER; + else if (the_same(csa->image, "binary")) + csa->token = T_BINARY; + else if (the_same(csa->image, "binaries")) + csa->token = T_BINARY; + else if (the_same(csa->image, "bin")) + csa->token = T_BINARY; + else if (the_same(csa->image, "end")) + csa->token = T_END; + } + } + else if (isdigit(csa->c) || csa->c == '.') + { /* numeric constant */ + csa->token = T_NUMBER; + /* scan integer part */ + while (isdigit(csa->c)) add_char(csa); + /* scan optional fractional part (it is mandatory, if there is + no integer part) */ + if (csa->c == '.') + { add_char(csa); + if (csa->imlen == 1 && !isdigit(csa->c)) + error(csa, "invalid use of decimal point\n"); + while (isdigit(csa->c)) add_char(csa); + } + /* scan optional decimal exponent */ + if (csa->c == 'e' || csa->c == 'E') + { add_char(csa); + if (csa->c == '+' || csa->c == '-') add_char(csa); + if (!isdigit(csa->c)) + error(csa, "numeric constant '%s' incomplete\n", + csa->image); + while (isdigit(csa->c)) add_char(csa); + } + /* convert the numeric constant to floating-point */ + if (str2num(csa->image, &csa->value)) + error(csa, "numeric constant '%s' out of range\n", + csa->image); + } + else if (csa->c == '+') + csa->token = T_PLUS, add_char(csa); + else if (csa->c == '-') + csa->token = T_MINUS, add_char(csa); + else if (csa->c == ':') + csa->token = T_COLON, add_char(csa); + else if (csa->c == '<') + { csa->token = T_LE, add_char(csa); + if (csa->c == '=') add_char(csa); + } + else if (csa->c == '>') + { csa->token = T_GE, add_char(csa); + if (csa->c == '=') add_char(csa); + } + else if (csa->c == '=') + { csa->token = T_EQ, add_char(csa); + if (csa->c == '<') + csa->token = T_LE, add_char(csa); + else if (csa->c == '>') + csa->token = T_GE, add_char(csa); + } + else + error(csa, "character '%c' not recognized\n", csa->c); + /* skip non-significant characters */ + while (csa->c == ' ') read_char(csa); + return; +} + +static int find_col(struct csa *csa, char *name) +{ /* find column by its symbolic name */ + int j; + j = glp_find_col(csa->P, name); + if (j == 0) + { /* not found; create new column */ + j = glp_add_cols(csa->P, 1); + glp_set_col_name(csa->P, j, name); + /* enlarge working arrays, if necessary */ + if (csa->n_max < j) + { int n_max = csa->n_max; + int *ind = csa->ind; + double *val = csa->val; + char *flag = csa->flag; + double *lb = csa->lb; + double *ub = csa->ub; + csa->n_max += csa->n_max; + csa->ind = xcalloc(1+csa->n_max, sizeof(int)); + memcpy(&csa->ind[1], &ind[1], n_max * sizeof(int)); + xfree(ind); + csa->val = xcalloc(1+csa->n_max, sizeof(double)); + memcpy(&csa->val[1], &val[1], n_max * sizeof(double)); + xfree(val); + csa->flag = xcalloc(1+csa->n_max, sizeof(char)); + memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); + memcpy(&csa->flag[1], &flag[1], n_max * sizeof(char)); + xfree(flag); + csa->lb = xcalloc(1+csa->n_max, sizeof(double)); + memcpy(&csa->lb[1], &lb[1], n_max * sizeof(double)); + xfree(lb); + csa->ub = xcalloc(1+csa->n_max, sizeof(double)); + memcpy(&csa->ub[1], &ub[1], n_max * sizeof(double)); + xfree(ub); + } + csa->lb[j] = +DBL_MAX, csa->ub[j] = -DBL_MAX; + } + return j; +} + +/*********************************************************************** +* parse_linear_form - parse linear form +* +* This routine parses the linear form using the following syntax: +* +* <variable> ::= <symbolic name> +* <coefficient> ::= <numeric constant> +* <term> ::= <variable> | <numeric constant> <variable> +* <linear form> ::= <term> | + <term> | - <term> | +* <linear form> + <term> | <linear form> - <term> +* +* The routine returns the number of terms in the linear form. */ + +static int parse_linear_form(struct csa *csa) +{ int j, k, len = 0, newlen; + double s, coef; +loop: /* parse an optional sign */ + if (csa->token == T_PLUS) + s = +1.0, scan_token(csa); + else if (csa->token == T_MINUS) + s = -1.0, scan_token(csa); + else + s = +1.0; + /* parse an optional coefficient */ + if (csa->token == T_NUMBER) + coef = csa->value, scan_token(csa); + else + coef = 1.0; + /* parse a variable name */ + if (csa->token != T_NAME) + error(csa, "missing variable name\n"); + /* find the corresponding column */ + j = find_col(csa, csa->image); + /* check if the variable is already used in the linear form */ + if (csa->flag[j]) + error(csa, "multiple use of variable '%s' not allowed\n", + csa->image); + /* add new term to the linear form */ + len++, csa->ind[len] = j, csa->val[len] = s * coef; + /* and mark that the variable is used in the linear form */ + csa->flag[j] = 1; + scan_token(csa); + /* if the next token is a sign, there is another term */ + if (csa->token == T_PLUS || csa->token == T_MINUS) goto loop; + /* clear marks of the variables used in the linear form */ + for (k = 1; k <= len; k++) csa->flag[csa->ind[k]] = 0; + /* remove zero coefficients */ + newlen = 0; + for (k = 1; k <= len; k++) + { if (csa->val[k] != 0.0) + { newlen++; + csa->ind[newlen] = csa->ind[k]; + csa->val[newlen] = csa->val[k]; + } + } + return newlen; +} + +/*********************************************************************** +* parse_objective - parse objective function +* +* This routine parses definition of the objective function using the +* following syntax: +* +* <obj sense> ::= minimize | minimum | min | maximize | maximum | max +* <obj name> ::= <empty> | <symbolic name> : +* <obj function> ::= <obj sense> <obj name> <linear form> */ + +static void parse_objective(struct csa *csa) +{ /* parse objective sense */ + int k, len; + /* parse the keyword 'minimize' or 'maximize' */ + if (csa->token == T_MINIMIZE) + glp_set_obj_dir(csa->P, GLP_MIN); + else if (csa->token == T_MAXIMIZE) + glp_set_obj_dir(csa->P, GLP_MAX); + else + xassert(csa != csa); + scan_token(csa); + /* parse objective name */ + if (csa->token == T_NAME && csa->c == ':') + { /* objective name is followed by a colon */ + glp_set_obj_name(csa->P, csa->image); + scan_token(csa); + xassert(csa->token == T_COLON); + scan_token(csa); + } + else + { /* objective name is not specified; use default */ + glp_set_obj_name(csa->P, "obj"); + } + /* parse linear form */ + len = parse_linear_form(csa); + for (k = 1; k <= len; k++) + glp_set_obj_coef(csa->P, csa->ind[k], csa->val[k]); + return; +} + +/*********************************************************************** +* parse_constraints - parse constraints section +* +* This routine parses the constraints section using the following +* syntax: +* +* <row name> ::= <empty> | <symbolic name> : +* <row sense> ::= < | <= | =< | > | >= | => | = +* <right-hand side> ::= <numeric constant> | + <numeric constant> | +* - <numeric constant> +* <constraint> ::= <row name> <linear form> <row sense> +* <right-hand side> +* <subject to> ::= subject to | such that | st | s.t. | st. +* <constraints section> ::= <subject to> <constraint> | +* <constraints section> <constraint> */ + +static void parse_constraints(struct csa *csa) +{ int i, len, type; + double s; + /* parse the keyword 'subject to' */ + xassert(csa->token == T_SUBJECT_TO); + scan_token(csa); +loop: /* create new row (constraint) */ + i = glp_add_rows(csa->P, 1); + /* parse row name */ + if (csa->token == T_NAME && csa->c == ':') + { /* row name is followed by a colon */ + if (glp_find_row(csa->P, csa->image) != 0) + error(csa, "constraint '%s' multiply defined\n", + csa->image); + glp_set_row_name(csa->P, i, csa->image); + scan_token(csa); + xassert(csa->token == T_COLON); + scan_token(csa); + } + else + { /* row name is not specified; use default */ + char name[50]; + sprintf(name, "r.%d", csa->count); + glp_set_row_name(csa->P, i, name); + } + /* parse linear form */ + len = parse_linear_form(csa); + glp_set_mat_row(csa->P, i, len, csa->ind, csa->val); + /* parse constraint sense */ + if (csa->token == T_LE) + type = GLP_UP, scan_token(csa); + else if (csa->token == T_GE) + type = GLP_LO, scan_token(csa); + else if (csa->token == T_EQ) + type = GLP_FX, scan_token(csa); + else + error(csa, "missing constraint sense\n"); + /* parse right-hand side */ + if (csa->token == T_PLUS) + s = +1.0, scan_token(csa); + else if (csa->token == T_MINUS) + s = -1.0, scan_token(csa); + else + s = +1.0; + if (csa->token != T_NUMBER) + error(csa, "missing right-hand side\n"); + glp_set_row_bnds(csa->P, i, type, s * csa->value, s * csa->value); + /* the rest of the current line must be empty */ + if (!(csa->c == '\n' || csa->c == EOF)) + error(csa, "invalid symbol(s) beyond right-hand side\n"); + scan_token(csa); + /* if the next token is a sign, numeric constant, or a symbolic + name, here is another constraint */ + if (csa->token == T_PLUS || csa->token == T_MINUS || + csa->token == T_NUMBER || csa->token == T_NAME) goto loop; + return; +} + +static void set_lower_bound(struct csa *csa, int j, double lb) +{ /* set lower bound of j-th variable */ + if (csa->lb[j] != +DBL_MAX && !csa->lb_warn) + { warning(csa, "lower bound of variable '%s' redefined\n", + glp_get_col_name(csa->P, j)); + csa->lb_warn = 1; + } + csa->lb[j] = lb; + return; +} + +static void set_upper_bound(struct csa *csa, int j, double ub) +{ /* set upper bound of j-th variable */ + if (csa->ub[j] != -DBL_MAX && !csa->ub_warn) + { warning(csa, "upper bound of variable '%s' redefined\n", + glp_get_col_name(csa->P, j)); + csa->ub_warn = 1; + } + csa->ub[j] = ub; + return; +} + +/*********************************************************************** +* parse_bounds - parse bounds section +* +* This routine parses the bounds section using the following syntax: +* +* <variable> ::= <symbolic name> +* <infinity> ::= infinity | inf +* <bound> ::= <numeric constant> | + <numeric constant> | +* - <numeric constant> | + <infinity> | - <infinity> +* <lt> ::= < | <= | =< +* <gt> ::= > | >= | => +* <bound definition> ::= <bound> <lt> <variable> <lt> <bound> | +* <bound> <lt> <variable> | <variable> <lt> <bound> | +* <variable> <gt> <bound> | <variable> = <bound> | <variable> free +* <bounds> ::= bounds | bound +* <bounds section> ::= <bounds> | +* <bounds section> <bound definition> */ + +static void parse_bounds(struct csa *csa) +{ int j, lb_flag; + double lb, s; + /* parse the keyword 'bounds' */ + xassert(csa->token == T_BOUNDS); + scan_token(csa); +loop: /* bound definition can start with a sign, numeric constant, or + a symbolic name */ + if (!(csa->token == T_PLUS || csa->token == T_MINUS || + csa->token == T_NUMBER || csa->token == T_NAME)) goto done; + /* parse bound definition */ + if (csa->token == T_PLUS || csa->token == T_MINUS) + { /* parse signed lower bound */ + lb_flag = 1; + s = (csa->token == T_PLUS ? +1.0 : -1.0); + scan_token(csa); + if (csa->token == T_NUMBER) + lb = s * csa->value, scan_token(csa); + else if (the_same(csa->image, "infinity") || + the_same(csa->image, "inf")) + { if (s > 0.0) + error(csa, "invalid use of '+inf' as lower bound\n"); + lb = -DBL_MAX, scan_token(csa); + } + else + error(csa, "missing lower bound\n"); + } + else if (csa->token == T_NUMBER) + { /* parse unsigned lower bound */ + lb_flag = 1; + lb = csa->value, scan_token(csa); + } + else + { /* lower bound is not specified */ + lb_flag = 0; + } + /* parse the token that should follow the lower bound */ + if (lb_flag) + { if (csa->token != T_LE) + error(csa, "missing '<', '<=', or '=<' after lower bound\n") + ; + scan_token(csa); + } + /* parse variable name */ + if (csa->token != T_NAME) + error(csa, "missing variable name\n"); + j = find_col(csa, csa->image); + /* set lower bound */ + if (lb_flag) set_lower_bound(csa, j, lb); + scan_token(csa); + /* parse the context that follows the variable name */ + if (csa->token == T_LE) + { /* parse upper bound */ + scan_token(csa); + if (csa->token == T_PLUS || csa->token == T_MINUS) + { /* parse signed upper bound */ + s = (csa->token == T_PLUS ? +1.0 : -1.0); + scan_token(csa); + if (csa->token == T_NUMBER) + { set_upper_bound(csa, j, s * csa->value); + scan_token(csa); + } + else if (the_same(csa->image, "infinity") || + the_same(csa->image, "inf")) + { if (s < 0.0) + error(csa, "invalid use of '-inf' as upper bound\n"); + set_upper_bound(csa, j, +DBL_MAX); + scan_token(csa); + } + else + error(csa, "missing upper bound\n"); + } + else if (csa->token == T_NUMBER) + { /* parse unsigned upper bound */ + set_upper_bound(csa, j, csa->value); + scan_token(csa); + } + else + error(csa, "missing upper bound\n"); + } + else if (csa->token == T_GE) + { /* parse lower bound */ + if (lb_flag) + { /* the context '... <= x >= ...' is invalid */ + error(csa, "invalid bound definition\n"); + } + scan_token(csa); + if (csa->token == T_PLUS || csa->token == T_MINUS) + { /* parse signed lower bound */ + s = (csa->token == T_PLUS ? +1.0 : -1.0); + scan_token(csa); + if (csa->token == T_NUMBER) + { set_lower_bound(csa, j, s * csa->value); + scan_token(csa); + } + else if (the_same(csa->image, "infinity") || + the_same(csa->image, "inf") == 0) + { if (s > 0.0) + error(csa, "invalid use of '+inf' as lower bound\n"); + set_lower_bound(csa, j, -DBL_MAX); + scan_token(csa); + } + else + error(csa, "missing lower bound\n"); + } + else if (csa->token == T_NUMBER) + { /* parse unsigned lower bound */ + set_lower_bound(csa, j, csa->value); + scan_token(csa); + } + else + error(csa, "missing lower bound\n"); + } + else if (csa->token == T_EQ) + { /* parse fixed value */ + if (lb_flag) + { /* the context '... <= x = ...' is invalid */ + error(csa, "invalid bound definition\n"); + } + scan_token(csa); + if (csa->token == T_PLUS || csa->token == T_MINUS) + { /* parse signed fixed value */ + s = (csa->token == T_PLUS ? +1.0 : -1.0); + scan_token(csa); + if (csa->token == T_NUMBER) + { set_lower_bound(csa, j, s * csa->value); + set_upper_bound(csa, j, s * csa->value); + scan_token(csa); + } + else + error(csa, "missing fixed value\n"); + } + else if (csa->token == T_NUMBER) + { /* parse unsigned fixed value */ + set_lower_bound(csa, j, csa->value); + set_upper_bound(csa, j, csa->value); + scan_token(csa); + } + else + error(csa, "missing fixed value\n"); + } + else if (the_same(csa->image, "free")) + { /* parse the keyword 'free' */ + if (lb_flag) + { /* the context '... <= x free ...' is invalid */ + error(csa, "invalid bound definition\n"); + } + set_lower_bound(csa, j, -DBL_MAX); + set_upper_bound(csa, j, +DBL_MAX); + scan_token(csa); + } + else if (!lb_flag) + { /* neither lower nor upper bounds are specified */ + error(csa, "invalid bound definition\n"); + } + goto loop; +done: return; +} + +/*********************************************************************** +* parse_integer - parse general, integer, or binary section +* +* <variable> ::= <symbolic name> +* <general> ::= general | generals | gen +* <integer> ::= integer | integers | int +* <binary> ::= binary | binaries | bin +* <section head> ::= <general> <integer> <binary> +* <additional section> ::= <section head> | +* <additional section> <variable> */ + +static void parse_integer(struct csa *csa) +{ int j, binary; + /* parse the keyword 'general', 'integer', or 'binary' */ + if (csa->token == T_GENERAL) + binary = 0, scan_token(csa); + else if (csa->token == T_INTEGER) + binary = 0, scan_token(csa); + else if (csa->token == T_BINARY) + binary = 1, scan_token(csa); + else + xassert(csa != csa); + /* parse list of variables (may be empty) */ + while (csa->token == T_NAME) + { /* find the corresponding column */ + j = find_col(csa, csa->image); + /* change kind of the variable */ + glp_set_col_kind(csa->P, j, GLP_IV); + /* set bounds for the binary variable */ + if (binary) +#if 0 /* 07/VIII-2013 */ + { set_lower_bound(csa, j, 0.0); + set_upper_bound(csa, j, 1.0); + } +#else + { set_lower_bound(csa, j, + csa->lb[j] == +DBL_MAX ? 0.0 : csa->lb[j]); + set_upper_bound(csa, j, + csa->ub[j] == -DBL_MAX ? 1.0 : csa->ub[j]); + } +#endif + scan_token(csa); + } + return; +} + +int glp_read_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) +{ /* read problem data in CPLEX LP format */ + glp_cpxcp _parm; + struct csa _csa, *csa = &_csa; + int ret; + xprintf("Reading problem data from '%s'...\n", fname); + if (parm == NULL) + glp_init_cpxcp(&_parm), parm = &_parm; + /* check control parameters */ + check_parm("glp_read_lp", parm); + /* initialize common storage area */ + csa->P = P; + csa->parm = parm; + csa->fname = fname; + csa->fp = NULL; + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->count = 0; + csa->c = '\n'; + csa->token = T_EOF; + csa->image[0] = '\0'; + csa->imlen = 0; + csa->value = 0.0; + csa->n_max = 100; + csa->ind = xcalloc(1+csa->n_max, sizeof(int)); + csa->val = xcalloc(1+csa->n_max, sizeof(double)); + csa->flag = xcalloc(1+csa->n_max, sizeof(char)); + memset(&csa->flag[1], 0, csa->n_max * sizeof(char)); + csa->lb = xcalloc(1+csa->n_max, sizeof(double)); + csa->ub = xcalloc(1+csa->n_max, sizeof(double)); +#if 1 /* 27/VII-2013 */ + csa->lb_warn = csa->ub_warn = 0; +#endif + /* erase problem object */ + glp_erase_prob(P); + glp_create_index(P); + /* open input CPLEX LP file */ + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* scan very first token */ + scan_token(csa); + /* parse definition of the objective function */ + if (!(csa->token == T_MINIMIZE || csa->token == T_MAXIMIZE)) + error(csa, "'minimize' or 'maximize' keyword missing\n"); + parse_objective(csa); + /* parse constraints section */ + if (csa->token != T_SUBJECT_TO) + error(csa, "constraints section missing\n"); + parse_constraints(csa); + /* parse optional bounds section */ + if (csa->token == T_BOUNDS) parse_bounds(csa); + /* parse optional general, integer, and binary sections */ + while (csa->token == T_GENERAL || + csa->token == T_INTEGER || + csa->token == T_BINARY) parse_integer(csa); + /* check for the keyword 'end' */ + if (csa->token == T_END) + scan_token(csa); + else if (csa->token == T_EOF) + warning(csa, "keyword 'end' missing\n"); + else + error(csa, "symbol '%s' in wrong position\n", csa->image); + /* nothing must follow the keyword 'end' (except comments) */ + if (csa->token != T_EOF) + error(csa, "extra symbol(s) detected beyond 'end'\n"); + /* set bounds of variables */ + { int j, type; + double lb, ub; + for (j = 1; j <= P->n; j++) + { lb = csa->lb[j]; + ub = csa->ub[j]; + if (lb == +DBL_MAX) lb = 0.0; /* default lb */ + if (ub == -DBL_MAX) ub = +DBL_MAX; /* default ub */ + if (lb == -DBL_MAX && ub == +DBL_MAX) + type = GLP_FR; + else if (ub == +DBL_MAX) + type = GLP_LO; + else if (lb == -DBL_MAX) + type = GLP_UP; + else if (lb != ub) + type = GLP_DB; + else + type = GLP_FX; + glp_set_col_bnds(csa->P, j, type, lb, ub); + } + } + /* print some statistics */ + xprintf("%d row%s, %d column%s, %d non-zero%s\n", + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", + P->nnz, P->nnz == 1 ? "" : "s"); + if (glp_get_num_int(P) > 0) + { int ni = glp_get_num_int(P); + int nb = glp_get_num_bin(P); + if (ni == 1) + { if (nb == 0) + xprintf("One variable is integer\n"); + else + xprintf("One variable is binary\n"); + } + else + { xprintf("%d integer variables, ", ni); + if (nb == 0) + xprintf("none"); + else if (nb == 1) + xprintf("one"); + else if (nb == ni) + xprintf("all"); + else + xprintf("%d", nb); + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); + } + } + xprintf("%d lines were read\n", csa->count); + /* problem data has been successfully read */ + glp_delete_index(P); + glp_sort_matrix(P); + ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); + xfree(csa->ind); + xfree(csa->val); + xfree(csa->flag); + xfree(csa->lb); + xfree(csa->ub); + if (ret != 0) glp_erase_prob(P); + return ret; +} + +/*********************************************************************** +* NAME +* +* glp_write_lp - write problem data in CPLEX LP format +* +* SYNOPSIS +* +* int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char +* *fname); +* +* DESCRIPTION +* +* The routine glp_write_lp writes problem data in CPLEX LP format to +* a text file. +* +* The parameter parm is a pointer to the structure glp_cpxcp, which +* specifies control parameters used by the routine. If parm is NULL, +* the routine uses default settings. +* +* The character string fname specifies a name of the text file to be +* written. +* +* RETURNS +* +* If the operation was successful, the routine glp_write_lp returns +* zero. Otherwise, it prints an error message and returns non-zero. */ + +#define csa csa1 + +struct csa +{ /* common storage area */ + glp_prob *P; + /* pointer to problem object */ + const glp_cpxcp *parm; + /* pointer to control parameters */ +}; + +static int check_name(char *name) +{ /* check if specified name is valid for CPLEX LP format */ + if (*name == '.') return 1; + if (isdigit((unsigned char)*name)) return 1; + for (; *name; name++) + { if (!isalnum((unsigned char)*name) && + strchr(CHAR_SET, (unsigned char)*name) == NULL) return 1; + } + return 0; /* name is ok */ +} + +static void adjust_name(char *name) +{ /* attempt to adjust specified name to make it valid for CPLEX LP + format */ + for (; *name; name++) + { if (*name == ' ') + *name = '_'; + else if (*name == '-') + *name = '~'; + else if (*name == '[') + *name = '('; + else if (*name == ']') + *name = ')'; + } + return; +} + +static char *row_name(struct csa *csa, int i, char rname[255+1]) +{ /* construct symbolic name of i-th row (constraint) */ + const char *name; + if (i == 0) + name = glp_get_obj_name(csa->P); + else + name = glp_get_row_name(csa->P, i); + if (name == NULL) goto fake; + strcpy(rname, name); + adjust_name(rname); + if (check_name(rname)) goto fake; + return rname; +fake: if (i == 0) + strcpy(rname, "obj"); + else + sprintf(rname, "r_%d", i); + return rname; +} + +static char *col_name(struct csa *csa, int j, char cname[255+1]) +{ /* construct symbolic name of j-th column (variable) */ + const char *name; + name = glp_get_col_name(csa->P, j); + if (name == NULL) goto fake; + strcpy(cname, name); + adjust_name(cname); + if (check_name(cname)) goto fake; + return cname; +#if 0 /* 18/I-2018 */ +fake: sprintf(cname, "x_%d", j); +#else +fake: /* construct fake name depending on column's attributes */ + { GLPCOL *col = csa->P->col[j]; + if (col->type == GLP_FX) + { /* fixed column */ + sprintf(cname, "s_%d", j); + } + else if (col->kind == GLP_CV) + { /* continuous variable */ + sprintf(cname, "x_%d", j); + } + else if (!(col->lb == 0 && col->ub == 1)) + { /* general (non-binary) integer variable */ + sprintf(cname, "y_%d", j); + } + else + { /* binary variable */ + sprintf(cname, "z_%d", j); + } + } +#endif + return cname; +} + +int glp_write_lp(glp_prob *P, const glp_cpxcp *parm, const char *fname) +{ /* write problem data in CPLEX LP format */ + glp_cpxcp _parm; + struct csa _csa, *csa = &_csa; + glp_file *fp; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij; + int i, j, len, flag, count, ret; + char line[1000+1], term[500+1], name[255+1]; + xprintf("Writing problem data to '%s'...\n", fname); + if (parm == NULL) + glp_init_cpxcp(&_parm), parm = &_parm; + /* check control parameters */ + check_parm("glp_write_lp", parm); + /* initialize common storage area */ + csa->P = P; + csa->parm = parm; + /* create output CPLEX LP file */ + fp = glp_open(fname, "w"), count = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* write problem name */ + xfprintf(fp, "\\* Problem: %s *\\\n", + P->name == NULL ? "Unknown" : P->name), count++; + xfprintf(fp, "\n"), count++; + /* the problem should contain at least one row and one column */ + if (!(P->m > 0 && P->n > 0)) + { xprintf("Warning: problem has no rows/columns\n"); + xfprintf(fp, "\\* WARNING: PROBLEM HAS NO ROWS/COLUMNS *\\\n"), + count++; + xfprintf(fp, "\n"), count++; + goto skip; + } + /* write the objective function definition */ + if (P->dir == GLP_MIN) + xfprintf(fp, "Minimize\n"), count++; + else if (P->dir == GLP_MAX) + xfprintf(fp, "Maximize\n"), count++; + else + xassert(P != P); + row_name(csa, 0, name); + sprintf(line, " %s:", name); + len = 0; + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + if (col->coef != 0.0 || col->ptr == NULL) + { len++; + col_name(csa, j, name); + if (col->coef == 0.0) + sprintf(term, " + 0 %s", name); /* empty column */ + else if (col->coef == +1.0) + sprintf(term, " + %s", name); + else if (col->coef == -1.0) + sprintf(term, " - %s", name); + else if (col->coef > 0.0) + sprintf(term, " + %.*g %s", DBL_DIG, +col->coef, name); + else + sprintf(term, " - %.*g %s", DBL_DIG, -col->coef, name); + if (strlen(line) + strlen(term) > 72) + xfprintf(fp, "%s\n", line), line[0] = '\0', count++; + strcat(line, term); + } + } + if (len == 0) + { /* empty objective */ + sprintf(term, " 0 %s", col_name(csa, 1, name)); + strcat(line, term); + } + xfprintf(fp, "%s\n", line), count++; + if (P->c0 != 0.0) + xfprintf(fp, "\\* constant term = %.*g *\\\n", DBL_DIG, P->c0), + count++; + xfprintf(fp, "\n"), count++; + /* write the constraints section */ + xfprintf(fp, "Subject To\n"), count++; + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + if (row->type == GLP_FR) continue; /* skip free row */ + row_name(csa, i, name); + sprintf(line, " %s:", name); + /* linear form */ + for (aij = row->ptr; aij != NULL; aij = aij->r_next) + { col_name(csa, aij->col->j, name); + if (aij->val == +1.0) + sprintf(term, " + %s", name); + else if (aij->val == -1.0) + sprintf(term, " - %s", name); + else if (aij->val > 0.0) + sprintf(term, " + %.*g %s", DBL_DIG, +aij->val, name); + else + sprintf(term, " - %.*g %s", DBL_DIG, -aij->val, name); + if (strlen(line) + strlen(term) > 72) + xfprintf(fp, "%s\n", line), line[0] = '\0', count++; + strcat(line, term); + } + if (row->type == GLP_DB) + { /* double-bounded (ranged) constraint */ + sprintf(term, " - ~r_%d", i); + if (strlen(line) + strlen(term) > 72) + xfprintf(fp, "%s\n", line), line[0] = '\0', count++; + strcat(line, term); + } + else if (row->ptr == NULL) + { /* empty constraint */ + sprintf(term, " 0 %s", col_name(csa, 1, name)); + strcat(line, term); + } + /* right hand-side */ + if (row->type == GLP_LO) + sprintf(term, " >= %.*g", DBL_DIG, row->lb); + else if (row->type == GLP_UP) + sprintf(term, " <= %.*g", DBL_DIG, row->ub); + else if (row->type == GLP_DB || row->type == GLP_FX) + sprintf(term, " = %.*g", DBL_DIG, row->lb); + else + xassert(row != row); + if (strlen(line) + strlen(term) > 72) + xfprintf(fp, "%s\n", line), line[0] = '\0', count++; + strcat(line, term); + xfprintf(fp, "%s\n", line), count++; + } + xfprintf(fp, "\n"), count++; + /* write the bounds section */ + flag = 0; + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + if (row->type != GLP_DB) continue; + if (!flag) + xfprintf(fp, "Bounds\n"), flag = 1, count++; + xfprintf(fp, " 0 <= ~r_%d <= %.*g\n", + i, DBL_DIG, row->ub - row->lb), count++; + } + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + if (col->type == GLP_LO && col->lb == 0.0) continue; + if (!flag) + xfprintf(fp, "Bounds\n"), flag = 1, count++; + col_name(csa, j, name); + if (col->type == GLP_FR) + xfprintf(fp, " %s free\n", name), count++; + else if (col->type == GLP_LO) + xfprintf(fp, " %s >= %.*g\n", + name, DBL_DIG, col->lb), count++; + else if (col->type == GLP_UP) + xfprintf(fp, " -Inf <= %s <= %.*g\n", + name, DBL_DIG, col->ub), count++; + else if (col->type == GLP_DB) + xfprintf(fp, " %.*g <= %s <= %.*g\n", + DBL_DIG, col->lb, name, DBL_DIG, col->ub), count++; + else if (col->type == GLP_FX) + xfprintf(fp, " %s = %.*g\n", + name, DBL_DIG, col->lb), count++; + else + xassert(col != col); + } + if (flag) xfprintf(fp, "\n"), count++; + /* write the integer section */ + flag = 0; + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + if (col->kind == GLP_CV) continue; + xassert(col->kind == GLP_IV); + if (!flag) + xfprintf(fp, "Generals\n"), flag = 1, count++; + xfprintf(fp, " %s\n", col_name(csa, j, name)), count++; + } + if (flag) xfprintf(fp, "\n"), count++; +skip: /* write the end keyword */ + xfprintf(fp, "End\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* problem data has been successfully written */ + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cpp.c b/glpk-5.0/src/api/cpp.c new file mode 100644 index 0000000..5473bf3 --- /dev/null +++ b/glpk-5.0/src/api/cpp.c @@ -0,0 +1,183 @@ +/* cpp.c (solve critical path problem) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_cpp - solve critical path problem +* +* SYNOPSIS +* +* double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls); +* +* DESCRIPTION +* +* The routine glp_cpp solves the critical path problem represented in +* the form of the project network. +* +* The parameter G is a pointer to the graph object, which specifies +* the project network. This graph must be acyclic. Multiple arcs are +* allowed being considered as single arcs. +* +* The parameter v_t specifies an offset of the field of type double +* in the vertex data block, which contains time t[i] >= 0 needed to +* perform corresponding job j. If v_t < 0, it is assumed that t[i] = 1 +* for all jobs. +* +* The parameter v_es specifies an offset of the field of type double +* in the vertex data block, to which the routine stores earliest start +* time for corresponding job. If v_es < 0, this time is not stored. +* +* The parameter v_ls specifies an offset of the field of type double +* in the vertex data block, to which the routine stores latest start +* time for corresponding job. If v_ls < 0, this time is not stored. +* +* RETURNS +* +* The routine glp_cpp returns the minimal project duration, that is, +* minimal time needed to perform all jobs in the project. */ + +static void sorting(glp_graph *G, int list[]); + +double glp_cpp(glp_graph *G, int v_t, int v_es, int v_ls) +{ glp_vertex *v; + glp_arc *a; + int i, j, k, nv, *list; + double temp, total, *t, *es, *ls; + if (v_t >= 0 && v_t > G->v_size - (int)sizeof(double)) + xerror("glp_cpp: v_t = %d; invalid offset\n", v_t); + if (v_es >= 0 && v_es > G->v_size - (int)sizeof(double)) + xerror("glp_cpp: v_es = %d; invalid offset\n", v_es); + if (v_ls >= 0 && v_ls > G->v_size - (int)sizeof(double)) + xerror("glp_cpp: v_ls = %d; invalid offset\n", v_ls); + nv = G->nv; + if (nv == 0) + { total = 0.0; + goto done; + } + /* allocate working arrays */ + t = xcalloc(1+nv, sizeof(double)); + es = xcalloc(1+nv, sizeof(double)); + ls = xcalloc(1+nv, sizeof(double)); + list = xcalloc(1+nv, sizeof(int)); + /* retrieve job times */ + for (i = 1; i <= nv; i++) + { v = G->v[i]; + if (v_t >= 0) + { memcpy(&t[i], (char *)v->data + v_t, sizeof(double)); + if (t[i] < 0.0) + xerror("glp_cpp: t[%d] = %g; invalid time\n", i, t[i]); + } + else + t[i] = 1.0; + } + /* perform topological sorting to determine the list of nodes + (jobs) such that if list[k] = i and list[kk] = j and there + exists arc (i->j), then k < kk */ + sorting(G, list); + /* FORWARD PASS */ + /* determine earliest start times */ + for (k = 1; k <= nv; k++) + { j = list[k]; + es[j] = 0.0; + for (a = G->v[j]->in; a != NULL; a = a->h_next) + { i = a->tail->i; + /* there exists arc (i->j) in the project network */ + temp = es[i] + t[i]; + if (es[j] < temp) es[j] = temp; + } + } + /* determine the minimal project duration */ + total = 0.0; + for (i = 1; i <= nv; i++) + { temp = es[i] + t[i]; + if (total < temp) total = temp; + } + /* BACKWARD PASS */ + /* determine latest start times */ + for (k = nv; k >= 1; k--) + { i = list[k]; + ls[i] = total - t[i]; + for (a = G->v[i]->out; a != NULL; a = a->t_next) + { j = a->head->i; + /* there exists arc (i->j) in the project network */ + temp = ls[j] - t[i]; + if (ls[i] > temp) ls[i] = temp; + } + /* avoid possible round-off errors */ + if (ls[i] < es[i]) ls[i] = es[i]; + } + /* store results, if necessary */ + if (v_es >= 0) + { for (i = 1; i <= nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_es, &es[i], sizeof(double)); + } + } + if (v_ls >= 0) + { for (i = 1; i <= nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_ls, &ls[i], sizeof(double)); + } + } + /* free working arrays */ + xfree(t); + xfree(es); + xfree(ls); + xfree(list); +done: return total; +} + +static void sorting(glp_graph *G, int list[]) +{ /* perform topological sorting to determine the list of nodes + (jobs) such that if list[k] = i and list[kk] = j and there + exists arc (i->j), then k < kk */ + int i, k, nv, v_size, *num; + void **save; + nv = G->nv; + v_size = G->v_size; + save = xcalloc(1+nv, sizeof(void *)); + num = xcalloc(1+nv, sizeof(int)); + G->v_size = sizeof(int); + for (i = 1; i <= nv; i++) + { save[i] = G->v[i]->data; + G->v[i]->data = &num[i]; + list[i] = 0; + } + if (glp_top_sort(G, 0) != 0) + xerror("glp_cpp: project network is not acyclic\n"); + G->v_size = v_size; + for (i = 1; i <= nv; i++) + { G->v[i]->data = save[i]; + k = num[i]; + xassert(1 <= k && k <= nv); + xassert(list[k] == 0); + list[k] = i; + } + xfree(save); + xfree(num); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/cpxbas.c b/glpk-5.0/src/api/cpxbas.c new file mode 100644 index 0000000..38ba3e4 --- /dev/null +++ b/glpk-5.0/src/api/cpxbas.c @@ -0,0 +1,267 @@ +/* cpxbas.c (construct Bixby's initial LP basis) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2008-2018 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +struct var +{ /* structural variable */ + int j; + /* ordinal number */ + double q; + /* penalty value */ +}; + +static int CDECL fcmp(const void *ptr1, const void *ptr2) +{ /* this routine is passed to the qsort() function */ + struct var *col1 = (void *)ptr1, *col2 = (void *)ptr2; + if (col1->q < col2->q) return -1; + if (col1->q > col2->q) return +1; + return 0; +} + +static int get_column(glp_prob *lp, int j, int ind[], double val[]) +{ /* Bixby's algorithm assumes that the constraint matrix is scaled + such that the maximum absolute value in every non-zero row and + column is 1 */ + int k, len; + double big; + len = glp_get_mat_col(lp, j, ind, val); + big = 0.0; + for (k = 1; k <= len; k++) + if (big < fabs(val[k])) big = fabs(val[k]); + if (big == 0.0) big = 1.0; + for (k = 1; k <= len; k++) val[k] /= big; + return len; +} + +static void cpx_basis(glp_prob *lp) +{ /* main routine */ + struct var *C, *C2, *C3, *C4; + int m, n, i, j, jk, k, l, ll, t, n2, n3, n4, type, len, *I, *r, + *ind; + double alpha, gamma, cmax, temp, *v, *val; + xprintf("Constructing initial basis...\n"); + /* determine the number of rows and columns */ + m = glp_get_num_rows(lp); + n = glp_get_num_cols(lp); + /* allocate working arrays */ + C = xcalloc(1+n, sizeof(struct var)); + I = xcalloc(1+m, sizeof(int)); + r = xcalloc(1+m, sizeof(int)); + v = xcalloc(1+m, sizeof(double)); + ind = xcalloc(1+m, sizeof(int)); + val = xcalloc(1+m, sizeof(double)); + /* make all auxiliary variables non-basic */ + for (i = 1; i <= m; i++) + { if (glp_get_row_type(lp, i) != GLP_DB) + glp_set_row_stat(lp, i, GLP_NS); + else if (fabs(glp_get_row_lb(lp, i)) <= + fabs(glp_get_row_ub(lp, i))) + glp_set_row_stat(lp, i, GLP_NL); + else + glp_set_row_stat(lp, i, GLP_NU); + } + /* make all structural variables non-basic */ + for (j = 1; j <= n; j++) + { if (glp_get_col_type(lp, j) != GLP_DB) + glp_set_col_stat(lp, j, GLP_NS); + else if (fabs(glp_get_col_lb(lp, j)) <= + fabs(glp_get_col_ub(lp, j))) + glp_set_col_stat(lp, j, GLP_NL); + else + glp_set_col_stat(lp, j, GLP_NU); + } + /* C2 is a set of free structural variables */ + n2 = 0, C2 = C + 0; + for (j = 1; j <= n; j++) + { type = glp_get_col_type(lp, j); + if (type == GLP_FR) + { n2++; + C2[n2].j = j; + C2[n2].q = 0.0; + } + } + /* C3 is a set of structural variables having excatly one (lower + or upper) bound */ + n3 = 0, C3 = C2 + n2; + for (j = 1; j <= n; j++) + { type = glp_get_col_type(lp, j); + if (type == GLP_LO) + { n3++; + C3[n3].j = j; + C3[n3].q = + glp_get_col_lb(lp, j); + } + else if (type == GLP_UP) + { n3++; + C3[n3].j = j; + C3[n3].q = - glp_get_col_ub(lp, j); + } + } + /* C4 is a set of structural variables having both (lower and + upper) bounds */ + n4 = 0, C4 = C3 + n3; + for (j = 1; j <= n; j++) + { type = glp_get_col_type(lp, j); + if (type == GLP_DB) + { n4++; + C4[n4].j = j; + C4[n4].q = glp_get_col_lb(lp, j) - glp_get_col_ub(lp, j); + } + } + /* compute gamma = max{|c[j]|: 1 <= j <= n} */ + gamma = 0.0; + for (j = 1; j <= n; j++) + { temp = fabs(glp_get_obj_coef(lp, j)); + if (gamma < temp) gamma = temp; + } + /* compute cmax */ + cmax = (gamma == 0.0 ? 1.0 : 1000.0 * gamma); + /* compute final penalty for all structural variables within sets + C2, C3, and C4 */ + switch (glp_get_obj_dir(lp)) + { case GLP_MIN: temp = +1.0; break; + case GLP_MAX: temp = -1.0; break; + default: xassert(lp != lp); + } + for (k = 1; k <= n2+n3+n4; k++) + { j = C[k].j; + C[k].q += (temp * glp_get_obj_coef(lp, j)) / cmax; + } + /* sort structural variables within C2, C3, and C4 in ascending + order of penalty value */ + qsort(C2+1, n2, sizeof(struct var), fcmp); + for (k = 1; k < n2; k++) xassert(C2[k].q <= C2[k+1].q); + qsort(C3+1, n3, sizeof(struct var), fcmp); + for (k = 1; k < n3; k++) xassert(C3[k].q <= C3[k+1].q); + qsort(C4+1, n4, sizeof(struct var), fcmp); + for (k = 1; k < n4; k++) xassert(C4[k].q <= C4[k+1].q); + /*** STEP 1 ***/ + for (i = 1; i <= m; i++) + { type = glp_get_row_type(lp, i); + if (type != GLP_FX) + { /* row i is either free or inequality constraint */ + glp_set_row_stat(lp, i, GLP_BS); + I[i] = 1; + r[i] = 1; + } + else + { /* row i is equality constraint */ + I[i] = 0; + r[i] = 0; + } + v[i] = +DBL_MAX; + } + /*** STEP 2 ***/ + for (k = 1; k <= n2+n3+n4; k++) + { jk = C[k].j; + len = get_column(lp, jk, ind, val); + /* let alpha = max{|A[l,jk]|: r[l] = 0} and let l' be such + that alpha = |A[l',jk]| */ + alpha = 0.0, ll = 0; + for (t = 1; t <= len; t++) + { l = ind[t]; + if (r[l] == 0 && alpha < fabs(val[t])) + alpha = fabs(val[t]), ll = l; + } + if (alpha >= 0.99) + { /* B := B union {jk} */ + glp_set_col_stat(lp, jk, GLP_BS); + I[ll] = 1; + v[ll] = alpha; + /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ + for (t = 1; t <= len; t++) + { l = ind[t]; + if (val[t] != 0.0) r[l]++; + } + /* continue to the next k */ + continue; + } + /* if |A[l,jk]| > 0.01 * v[l] for some l, continue to the + next k */ + for (t = 1; t <= len; t++) + { l = ind[t]; + if (fabs(val[t]) > 0.01 * v[l]) break; + } + if (t <= len) continue; + /* otherwise, let alpha = max{|A[l,jk]|: I[l] = 0} and let l' + be such that alpha = |A[l',jk]| */ + alpha = 0.0, ll = 0; + for (t = 1; t <= len; t++) + { l = ind[t]; + if (I[l] == 0 && alpha < fabs(val[t])) + alpha = fabs(val[t]), ll = l; + } + /* if alpha = 0, continue to the next k */ + if (alpha == 0.0) continue; + /* B := B union {jk} */ + glp_set_col_stat(lp, jk, GLP_BS); + I[ll] = 1; + v[ll] = alpha; + /* r[l] := r[l] + 1 for all l such that |A[l,jk]| != 0 */ + for (t = 1; t <= len; t++) + { l = ind[t]; + if (val[t] != 0.0) r[l]++; + } + } + /*** STEP 3 ***/ + /* add an artificial variable (auxiliary variable for equality + constraint) to cover each remaining uncovered row */ + for (i = 1; i <= m; i++) + if (I[i] == 0) glp_set_row_stat(lp, i, GLP_BS); + /* free working arrays */ + xfree(C); + xfree(I); + xfree(r); + xfree(v); + xfree(ind); + xfree(val); + return; +} + +/*********************************************************************** +* NAME +* +* glp_cpx_basis - construct Bixby's initial LP basis +* +* SYNOPSIS +* +* void glp_cpx_basis(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_cpx_basis constructs an advanced initial basis for +* the specified problem object. +* +* The routine is based on Bixby's algorithm described in the paper: +* +* Robert E. Bixby. Implementing the Simplex Method: The Initial Basis. +* ORSA Journal on Computing, Vol. 4, No. 3, 1992, pp. 267-84. */ + +void glp_cpx_basis(glp_prob *lp) +{ if (lp->m == 0 || lp->n == 0) + glp_std_basis(lp); + else + cpx_basis(lp); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/graph.c b/glpk-5.0/src/api/graph.c new file mode 100644 index 0000000..a522282 --- /dev/null +++ b/glpk-5.0/src/api/graph.c @@ -0,0 +1,502 @@ +/* graph.c (basic graph routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "avl.h" +#include "dmp.h" +#include "env.h" +#include "glpk.h" + +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ + +#define NV_MAX 100000000 /* = 100*10^6 */ +/* maximal number of vertices in the graph */ + +#define NA_MAX 500000000 /* = 500*10^6 */ +/* maximal number of arcs in the graph */ + +/*********************************************************************** +* NAME +* +* glp_create_graph - create graph +* +* SYNOPSIS +* +* glp_graph *glp_create_graph(int v_size, int a_size); +* +* DESCRIPTION +* +* The routine creates a new graph, which initially is empty, i.e. has +* no vertices and arcs. +* +* The parameter v_size specifies the size of data associated with each +* vertex of the graph (0 to 256 bytes). +* +* The parameter a_size specifies the size of data associated with each +* arc of the graph (0 to 256 bytes). +* +* RETURNS +* +* The routine returns a pointer to the graph created. */ + +static void create_graph(glp_graph *G, int v_size, int a_size) +{ G->pool = dmp_create_pool(); + G->name = NULL; + G->nv_max = 50; + G->nv = G->na = 0; + G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); + G->index = NULL; + G->v_size = v_size; + G->a_size = a_size; + return; +} + +glp_graph *glp_create_graph(int v_size, int a_size) +{ glp_graph *G; + if (!(0 <= v_size && v_size <= 256)) + xerror("glp_create_graph: v_size = %d; invalid size of vertex " + "data\n", v_size); + if (!(0 <= a_size && a_size <= 256)) + xerror("glp_create_graph: a_size = %d; invalid size of arc dat" + "a\n", a_size); + G = xmalloc(sizeof(glp_graph)); + create_graph(G, v_size, a_size); + return G; +} + +/*********************************************************************** +* NAME +* +* glp_set_graph_name - assign (change) graph name +* +* SYNOPSIS +* +* void glp_set_graph_name(glp_graph *G, const char *name); +* +* DESCRIPTION +* +* The routine glp_set_graph_name assigns a symbolic name specified by +* the character string name (1 to 255 chars) to the graph. +* +* If the parameter name is NULL or an empty string, the routine erases +* the existing symbolic name of the graph. */ + +void glp_set_graph_name(glp_graph *G, const char *name) +{ if (G->name != NULL) + { dmp_free_atom(G->pool, G->name, strlen(G->name)+1); + G->name = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int j; + for (j = 0; name[j] != '\0'; j++) + { if (j == 256) + xerror("glp_set_graph_name: graph name too long\n"); + if (iscntrl((unsigned char)name[j])) + xerror("glp_set_graph_name: graph name contains invalid " + "character(s)\n"); + } + G->name = dmp_get_atom(G->pool, strlen(name)+1); + strcpy(G->name, name); + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_add_vertices - add new vertices to graph +* +* SYNOPSIS +* +* int glp_add_vertices(glp_graph *G, int nadd); +* +* DESCRIPTION +* +* The routine glp_add_vertices adds nadd vertices to the specified +* graph. New vertices are always added to the end of the vertex list, +* so ordinal numbers of existing vertices remain unchanged. +* +* Being added each new vertex is isolated (has no incident arcs). +* +* RETURNS +* +* The routine glp_add_vertices returns an ordinal number of the first +* new vertex added to the graph. */ + +int glp_add_vertices(glp_graph *G, int nadd) +{ int i, nv_new; + if (nadd < 1) + xerror("glp_add_vertices: nadd = %d; invalid number of vertice" + "s\n", nadd); + if (nadd > NV_MAX - G->nv) + xerror("glp_add_vertices: nadd = %d; too many vertices\n", + nadd); + /* determine new number of vertices */ + nv_new = G->nv + nadd; + /* increase the room, if necessary */ + if (G->nv_max < nv_new) + { glp_vertex **save = G->v; + while (G->nv_max < nv_new) + { G->nv_max += G->nv_max; + xassert(G->nv_max > 0); + } + G->v = xcalloc(1+G->nv_max, sizeof(glp_vertex *)); + memcpy(&G->v[1], &save[1], G->nv * sizeof(glp_vertex *)); + xfree(save); + } + /* add new vertices to the end of the vertex list */ + for (i = G->nv+1; i <= nv_new; i++) + { glp_vertex *v; + G->v[i] = v = dmp_get_atom(G->pool, sizeof(glp_vertex)); + v->i = i; + v->name = NULL; + v->entry = NULL; + if (G->v_size == 0) + v->data = NULL; + else + { v->data = dmp_get_atom(G->pool, G->v_size); + memset(v->data, 0, G->v_size); + } + v->temp = NULL; + v->in = v->out = NULL; + } + /* set new number of vertices */ + G->nv = nv_new; + /* return the ordinal number of the first vertex added */ + return nv_new - nadd + 1; +} + +/**********************************************************************/ + +void glp_set_vertex_name(glp_graph *G, int i, const char *name) +{ /* assign (change) vertex name */ + glp_vertex *v; + if (!(1 <= i && i <= G->nv)) + xerror("glp_set_vertex_name: i = %d; vertex number out of rang" + "e\n", i); + v = G->v[i]; + if (v->name != NULL) + { if (v->entry != NULL) + { xassert(G->index != NULL); + avl_delete_node(G->index, v->entry); + v->entry = NULL; + } + dmp_free_atom(G->pool, v->name, strlen(v->name)+1); + v->name = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int k; + for (k = 0; name[k] != '\0'; k++) + { if (k == 256) + xerror("glp_set_vertex_name: i = %d; vertex name too lon" + "g\n", i); + if (iscntrl((unsigned char)name[k])) + xerror("glp_set_vertex_name: i = %d; vertex name contain" + "s invalid character(s)\n", i); + } + v->name = dmp_get_atom(G->pool, strlen(name)+1); + strcpy(v->name, name); + if (G->index != NULL) + { xassert(v->entry == NULL); + v->entry = avl_insert_node(G->index, v->name); + avl_set_node_link(v->entry, v); + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_add_arc - add new arc to graph +* +* SYNOPSIS +* +* glp_arc *glp_add_arc(glp_graph *G, int i, int j); +* +* DESCRIPTION +* +* The routine glp_add_arc adds a new arc to the specified graph. +* +* The parameters i and j specify the ordinal numbers of, resp., tail +* and head vertices of the arc. Note that self-loops and multiple arcs +* are allowed. +* +* RETURNS +* +* The routine glp_add_arc returns a pointer to the arc added. */ + +glp_arc *glp_add_arc(glp_graph *G, int i, int j) +{ glp_arc *a; + if (!(1 <= i && i <= G->nv)) + xerror("glp_add_arc: i = %d; tail vertex number out of range\n" + , i); + if (!(1 <= j && j <= G->nv)) + xerror("glp_add_arc: j = %d; head vertex number out of range\n" + , j); + if (G->na == NA_MAX) + xerror("glp_add_arc: too many arcs\n"); + a = dmp_get_atom(G->pool, sizeof(glp_arc)); + a->tail = G->v[i]; + a->head = G->v[j]; + if (G->a_size == 0) + a->data = NULL; + else + { a->data = dmp_get_atom(G->pool, G->a_size); + memset(a->data, 0, G->a_size); + } + a->temp = NULL; + a->t_prev = NULL; + a->t_next = G->v[i]->out; + if (a->t_next != NULL) a->t_next->t_prev = a; + a->h_prev = NULL; + a->h_next = G->v[j]->in; + if (a->h_next != NULL) a->h_next->h_prev = a; + G->v[i]->out = G->v[j]->in = a; + G->na++; + return a; +} + +/*********************************************************************** +* NAME +* +* glp_del_vertices - delete vertices from graph +* +* SYNOPSIS +* +* void glp_del_vertices(glp_graph *G, int ndel, const int num[]); +* +* DESCRIPTION +* +* The routine glp_del_vertices deletes vertices along with all +* incident arcs from the specified graph. Ordinal numbers of vertices +* to be deleted should be placed in locations num[1], ..., num[ndel], +* ndel > 0. +* +* Note that deleting vertices involves changing ordinal numbers of +* other vertices remaining in the graph. New ordinal numbers of the +* remaining vertices are assigned under the assumption that the +* original order of vertices is not changed. */ + +void glp_del_vertices(glp_graph *G, int ndel, const int num[]) +{ glp_vertex *v; + int i, k, nv_new; + /* scan the list of vertices to be deleted */ + if (!(1 <= ndel && ndel <= G->nv)) + xerror("glp_del_vertices: ndel = %d; invalid number of vertice" + "s\n", ndel); + for (k = 1; k <= ndel; k++) + { /* take the number of vertex to be deleted */ + i = num[k]; + /* obtain pointer to i-th vertex */ + if (!(1 <= i && i <= G->nv)) + xerror("glp_del_vertices: num[%d] = %d; vertex number out o" + "f range\n", k, i); + v = G->v[i]; + /* check that the vertex is not marked yet */ + if (v->i == 0) + xerror("glp_del_vertices: num[%d] = %d; duplicate vertex nu" + "mbers not allowed\n", k, i); + /* erase symbolic name assigned to the vertex */ + glp_set_vertex_name(G, i, NULL); + xassert(v->name == NULL); + xassert(v->entry == NULL); + /* free vertex data, if allocated */ + if (v->data != NULL) + dmp_free_atom(G->pool, v->data, G->v_size); + /* delete all incoming arcs */ + while (v->in != NULL) + glp_del_arc(G, v->in); + /* delete all outgoing arcs */ + while (v->out != NULL) + glp_del_arc(G, v->out); + /* mark the vertex to be deleted */ + v->i = 0; + } + /* delete all marked vertices from the vertex list */ + nv_new = 0; + for (i = 1; i <= G->nv; i++) + { /* obtain pointer to i-th vertex */ + v = G->v[i]; + /* check if the vertex is marked */ + if (v->i == 0) + { /* it is marked, delete it */ + dmp_free_atom(G->pool, v, sizeof(glp_vertex)); + } + else + { /* it is not marked, keep it */ + v->i = ++nv_new; + G->v[v->i] = v; + } + } + /* set new number of vertices in the graph */ + G->nv = nv_new; + return; +} + +/*********************************************************************** +* NAME +* +* glp_del_arc - delete arc from graph +* +* SYNOPSIS +* +* void glp_del_arc(glp_graph *G, glp_arc *a); +* +* DESCRIPTION +* +* The routine glp_del_arc deletes an arc from the specified graph. +* The arc to be deleted must exist. */ + +void glp_del_arc(glp_graph *G, glp_arc *a) +{ /* some sanity checks */ + xassert(G->na > 0); + xassert(1 <= a->tail->i && a->tail->i <= G->nv); + xassert(a->tail == G->v[a->tail->i]); + xassert(1 <= a->head->i && a->head->i <= G->nv); + xassert(a->head == G->v[a->head->i]); + /* remove the arc from the list of incoming arcs */ + if (a->h_prev == NULL) + a->head->in = a->h_next; + else + a->h_prev->h_next = a->h_next; + if (a->h_next == NULL) + ; + else + a->h_next->h_prev = a->h_prev; + /* remove the arc from the list of outgoing arcs */ + if (a->t_prev == NULL) + a->tail->out = a->t_next; + else + a->t_prev->t_next = a->t_next; + if (a->t_next == NULL) + ; + else + a->t_next->t_prev = a->t_prev; + /* free arc data, if allocated */ + if (a->data != NULL) + dmp_free_atom(G->pool, a->data, G->a_size); + /* delete the arc from the graph */ + dmp_free_atom(G->pool, a, sizeof(glp_arc)); + G->na--; + return; +} + +/*********************************************************************** +* NAME +* +* glp_erase_graph - erase graph content +* +* SYNOPSIS +* +* void glp_erase_graph(glp_graph *G, int v_size, int a_size); +* +* DESCRIPTION +* +* The routine glp_erase_graph erases the content of the specified +* graph. The effect of this operation is the same as if the graph +* would be deleted with the routine glp_delete_graph and then created +* anew with the routine glp_create_graph, with exception that the +* handle (pointer) to the graph remains valid. */ + +static void delete_graph(glp_graph *G) +{ dmp_delete_pool(G->pool); + xfree(G->v); + if (G->index != NULL) avl_delete_tree(G->index); + return; +} + +void glp_erase_graph(glp_graph *G, int v_size, int a_size) +{ if (!(0 <= v_size && v_size <= 256)) + xerror("glp_erase_graph: v_size = %d; invalid size of vertex d" + "ata\n", v_size); + if (!(0 <= a_size && a_size <= 256)) + xerror("glp_erase_graph: a_size = %d; invalid size of arc data" + "\n", a_size); + delete_graph(G); + create_graph(G, v_size, a_size); + return; +} + +/*********************************************************************** +* NAME +* +* glp_delete_graph - delete graph +* +* SYNOPSIS +* +* void glp_delete_graph(glp_graph *G); +* +* DESCRIPTION +* +* The routine glp_delete_graph deletes the specified graph and frees +* all the memory allocated to this program object. */ + +void glp_delete_graph(glp_graph *G) +{ delete_graph(G); + xfree(G); + return; +} + +/**********************************************************************/ + +void glp_create_v_index(glp_graph *G) +{ /* create vertex name index */ + glp_vertex *v; + int i; + if (G->index == NULL) + { G->index = avl_create_tree(avl_strcmp, NULL); + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + xassert(v->entry == NULL); + if (v->name != NULL) + { v->entry = avl_insert_node(G->index, v->name); + avl_set_node_link(v->entry, v); + } + } + } + return; +} + +int glp_find_vertex(glp_graph *G, const char *name) +{ /* find vertex by its name */ + AVLNODE *node; + int i = 0; + if (G->index == NULL) + xerror("glp_find_vertex: vertex name index does not exist\n"); + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) + { node = avl_find_node(G->index, name); + if (node != NULL) + i = ((glp_vertex *)avl_get_node_link(node))->i; + } + return i; +} + +void glp_delete_v_index(glp_graph *G) +{ /* delete vertex name index */ + int i; + if (G->index != NULL) + { avl_delete_tree(G->index), G->index = NULL; + for (i = 1; i <= G->nv; i++) G->v[i]->entry = NULL; + } + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/gridgen.c b/glpk-5.0/src/api/gridgen.c new file mode 100644 index 0000000..9df454b --- /dev/null +++ b/glpk-5.0/src/api/gridgen.c @@ -0,0 +1,20 @@ +/* gridgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_gridgen(glp_graph *G_, int v_rhs_, int a_cap_, int a_cost_, + const int parm[1+14]) +{ static const char func[] = "glp_gridgen"; + xassert(G_ == G_); + xassert(v_rhs_ == v_rhs_); + xassert(a_cap_ == a_cap_); + xassert(a_cost_ == a_cost_); + xassert(parm == parm); + xerror("%s: sorry, this routine is temporarily disabled due to li" + "censing problems\n", func); + abort(); + return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/intfeas1.c b/glpk-5.0/src/api/intfeas1.c new file mode 100644 index 0000000..d500251 --- /dev/null +++ b/glpk-5.0/src/api/intfeas1.c @@ -0,0 +1,265 @@ +/* intfeas1.c (solve integer feasibility problem) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2011-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "npp.h" + +int glp_intfeas1(glp_prob *P, int use_bound, int obj_bound) +{ /* solve integer feasibility problem */ + NPP *npp = NULL; + glp_prob *mip = NULL; + int *obj_ind = NULL; + double *obj_val = NULL; + int obj_row = 0; + int i, j, k, obj_len, temp, ret; +#if 0 /* 04/IV-2016 */ + /* check the problem object */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_intfeas1: P = %p; invalid problem object\n", + P); +#endif + if (P->tree != NULL) + xerror("glp_intfeas1: operation not allowed\n"); + /* integer solution is currently undefined */ + P->mip_stat = GLP_UNDEF; + P->mip_obj = 0.0; + /* check columns (variables) */ + for (j = 1; j <= P->n; j++) + { GLPCOL *col = P->col[j]; +#if 0 /* binarization is not yet implemented */ + if (!(col->kind == GLP_IV || col->type == GLP_FX)) + { xprintf("glp_intfeas1: column %d: non-integer non-fixed var" + "iable not allowed\n", j); +#else + if (!((col->kind == GLP_IV && col->lb == 0.0 && col->ub == 1.0) + || col->type == GLP_FX)) + { xprintf("glp_intfeas1: column %d: non-binary non-fixed vari" + "able not allowed\n", j); +#endif + ret = GLP_EDATA; + goto done; + } + temp = (int)col->lb; + if ((double)temp != col->lb) + { if (col->type == GLP_FX) + xprintf("glp_intfeas1: column %d: fixed value %g is non-" + "integer or out of range\n", j, col->lb); + else + xprintf("glp_intfeas1: column %d: lower bound %g is non-" + "integer or out of range\n", j, col->lb); + ret = GLP_EDATA; + goto done; + } + temp = (int)col->ub; + if ((double)temp != col->ub) + { xprintf("glp_intfeas1: column %d: upper bound %g is non-int" + "eger or out of range\n", j, col->ub); + ret = GLP_EDATA; + goto done; + } + if (col->type == GLP_DB && col->lb > col->ub) + { xprintf("glp_intfeas1: column %d: lower bound %g is greater" + " than upper bound %g\n", j, col->lb, col->ub); + ret = GLP_EBOUND; + goto done; + } + } + /* check rows (constraints) */ + for (i = 1; i <= P->m; i++) + { GLPROW *row = P->row[i]; + GLPAIJ *aij; + for (aij = row->ptr; aij != NULL; aij = aij->r_next) + { temp = (int)aij->val; + if ((double)temp != aij->val) + { xprintf("glp_intfeas1: row = %d, column %d: constraint c" + "oefficient %g is non-integer or out of range\n", + i, aij->col->j, aij->val); + ret = GLP_EDATA; + goto done; + } + } + temp = (int)row->lb; + if ((double)temp != row->lb) + { if (row->type == GLP_FX) + xprintf("glp_intfeas1: row = %d: fixed value %g is non-i" + "nteger or out of range\n", i, row->lb); + else + xprintf("glp_intfeas1: row = %d: lower bound %g is non-i" + "nteger or out of range\n", i, row->lb); + ret = GLP_EDATA; + goto done; + } + temp = (int)row->ub; + if ((double)temp != row->ub) + { xprintf("glp_intfeas1: row = %d: upper bound %g is non-inte" + "ger or out of range\n", i, row->ub); + ret = GLP_EDATA; + goto done; + } + if (row->type == GLP_DB && row->lb > row->ub) + { xprintf("glp_intfeas1: row %d: lower bound %g is greater th" + "an upper bound %g\n", i, row->lb, row->ub); + ret = GLP_EBOUND; + goto done; + } + } + /* check the objective function */ +#if 1 /* 08/I-2017 by cmatraki & mao */ + if (!use_bound) + { /* skip check if no obj. bound is specified */ + goto skip; + } +#endif + temp = (int)P->c0; + if ((double)temp != P->c0) + { xprintf("glp_intfeas1: objective constant term %g is non-integ" + "er or out of range\n", P->c0); + ret = GLP_EDATA; + goto done; + } + for (j = 1; j <= P->n; j++) + { temp = (int)P->col[j]->coef; + if ((double)temp != P->col[j]->coef) + { xprintf("glp_intfeas1: column %d: objective coefficient is " + "non-integer or out of range\n", j, P->col[j]->coef); + ret = GLP_EDATA; + goto done; + } + } +#if 1 /* 08/I-2017 by cmatraki & mao */ +skip: ; +#endif + /* save the objective function and set it to zero */ + obj_ind = xcalloc(1+P->n, sizeof(int)); + obj_val = xcalloc(1+P->n, sizeof(double)); + obj_len = 0; + obj_ind[0] = 0; + obj_val[0] = P->c0; + P->c0 = 0.0; + for (j = 1; j <= P->n; j++) + { if (P->col[j]->coef != 0.0) + { obj_len++; + obj_ind[obj_len] = j; + obj_val[obj_len] = P->col[j]->coef; + P->col[j]->coef = 0.0; + } + } + /* add inequality to bound the objective function, if required */ + if (!use_bound) + xprintf("Will search for ANY feasible solution\n"); + else + { xprintf("Will search only for solution not worse than %d\n", + obj_bound); + obj_row = glp_add_rows(P, 1); + glp_set_mat_row(P, obj_row, obj_len, obj_ind, obj_val); + if (P->dir == GLP_MIN) + glp_set_row_bnds(P, obj_row, + GLP_UP, 0.0, (double)obj_bound - obj_val[0]); + else if (P->dir == GLP_MAX) + glp_set_row_bnds(P, obj_row, + GLP_LO, (double)obj_bound - obj_val[0], 0.0); + else + xassert(P != P); + } + /* create preprocessor workspace */ + xprintf("Translating to CNF-SAT...\n"); + xprintf("Original problem has %d row%s, %d column%s, and %d non-z" + "ero%s\n", P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : + "s", P->nnz, P->nnz == 1 ? "" : "s"); + npp = npp_create_wksp(); + /* load the original problem into the preprocessor workspace */ + npp_load_prob(npp, P, GLP_OFF, GLP_MIP, GLP_OFF); + /* perform translation to SAT-CNF problem instance */ + ret = npp_sat_encode_prob(npp); + if (ret == 0) + ; + else if (ret == GLP_ENOPFS) + xprintf("PROBLEM HAS NO INTEGER FEASIBLE SOLUTION\n"); + else if (ret == GLP_ERANGE) + xprintf("glp_intfeas1: translation to SAT-CNF failed because o" + "f integer overflow\n"); + else + xassert(ret != ret); + if (ret != 0) + goto done; + /* build SAT-CNF problem instance and try to solve it */ + mip = glp_create_prob(); + npp_build_prob(npp, mip); + ret = glp_minisat1(mip); + /* only integer feasible solution can be postprocessed */ + if (!(mip->mip_stat == GLP_OPT || mip->mip_stat == GLP_FEAS)) + { P->mip_stat = mip->mip_stat; + goto done; + } + /* postprocess the solution found */ + npp_postprocess(npp, mip); + /* the transformed problem is no longer needed */ + glp_delete_prob(mip), mip = NULL; + /* store solution to the original problem object */ + npp_unload_sol(npp, P); + /* change the solution status to 'integer feasible' */ + P->mip_stat = GLP_FEAS; + /* check integer feasibility */ + for (i = 1; i <= P->m; i++) + { GLPROW *row; + GLPAIJ *aij; + double sum; + row = P->row[i]; + sum = 0.0; + for (aij = row->ptr; aij != NULL; aij = aij->r_next) + sum += aij->val * aij->col->mipx; + xassert(sum == row->mipx); + if (row->type == GLP_LO || row->type == GLP_DB || + row->type == GLP_FX) + xassert(sum >= row->lb); + if (row->type == GLP_UP || row->type == GLP_DB || + row->type == GLP_FX) + xassert(sum <= row->ub); + } + /* compute value of the original objective function */ + P->mip_obj = obj_val[0]; + for (k = 1; k <= obj_len; k++) + P->mip_obj += obj_val[k] * P->col[obj_ind[k]]->mipx; + xprintf("Objective value = %17.9e\n", P->mip_obj); +done: /* delete the transformed problem, if it exists */ + if (mip != NULL) + glp_delete_prob(mip); + /* delete the preprocessor workspace, if it exists */ + if (npp != NULL) + npp_delete_wksp(npp); + /* remove inequality used to bound the objective function */ + if (obj_row > 0) + { int ind[1+1]; + ind[1] = obj_row; + glp_del_rows(P, 1, ind); + } + /* restore the original objective function */ + if (obj_ind != NULL) + { P->c0 = obj_val[0]; + for (k = 1; k <= obj_len; k++) + P->col[obj_ind[k]]->coef = obj_val[k]; + xfree(obj_ind); + xfree(obj_val); + } + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/maxffalg.c b/glpk-5.0/src/api/maxffalg.c new file mode 100644 index 0000000..5b66a6c --- /dev/null +++ b/glpk-5.0/src/api/maxffalg.c @@ -0,0 +1,128 @@ +/* maxffalg.c (find maximal flow with Ford-Fulkerson algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ffalg.h" +#include "glpk.h" + +int glp_maxflow_ffalg(glp_graph *G, int s, int t, int a_cap, + double *sol, int a_x, int v_cut) +{ /* find maximal flow with Ford-Fulkerson algorithm */ + glp_vertex *v; + glp_arc *a; + int nv, na, i, k, flag, *tail, *head, *cap, *x, ret; + char *cut; + double temp; + if (!(1 <= s && s <= G->nv)) + xerror("glp_maxflow_ffalg: s = %d; source node number out of r" + "ange\n", s); + if (!(1 <= t && t <= G->nv)) + xerror("glp_maxflow_ffalg: t = %d: sink node number out of ran" + "ge\n", t); + if (s == t) + xerror("glp_maxflow_ffalg: s = t = %d; source and sink nodes m" + "ust be distinct\n", s); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_maxflow_ffalg: a_cap = %d; invalid offset\n", + a_cap); + if (v_cut >= 0 && v_cut > G->v_size - (int)sizeof(int)) + xerror("glp_maxflow_ffalg: v_cut = %d; invalid offset\n", + v_cut); + /* allocate working arrays */ + nv = G->nv; + na = G->na; + tail = xcalloc(1+na, sizeof(int)); + head = xcalloc(1+na, sizeof(int)); + cap = xcalloc(1+na, sizeof(int)); + x = xcalloc(1+na, sizeof(int)); + if (v_cut < 0) + cut = NULL; + else + cut = xcalloc(1+nv, sizeof(char)); + /* copy the flow network */ + k = 0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + tail[k] = a->tail->i; + head[k] = a->head->i; + if (tail[k] == head[k]) + { ret = GLP_EDATA; + goto done; + } + if (a_cap >= 0) + memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); + else + temp = 1.0; + if (!(0.0 <= temp && temp <= (double)INT_MAX && + temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + cap[k] = (int)temp; + } + } + xassert(k == na); + /* find maximal flow in the flow network */ + ffalg(nv, na, tail, head, s, t, cap, x, cut); + ret = 0; + /* store solution components */ + /* (objective function = total flow through the network) */ + if (sol != NULL) + { temp = 0.0; + for (k = 1; k <= na; k++) + { if (tail[k] == s) + temp += (double)x[k]; + else if (head[k] == s) + temp -= (double)x[k]; + } + *sol = temp; + } + /* (arc flows) */ + if (a_x >= 0) + { k = 0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { temp = (double)x[++k]; + memcpy((char *)a->data + a_x, &temp, sizeof(double)); + } + } + } + /* (node flags) */ + if (v_cut >= 0) + { for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + flag = cut[i]; + memcpy((char *)v->data + v_cut, &flag, sizeof(int)); + } + } +done: /* free working arrays */ + xfree(tail); + xfree(head); + xfree(cap); + xfree(x); + if (cut != NULL) xfree(cut); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/maxflp.c b/glpk-5.0/src/api/maxflp.c new file mode 100644 index 0000000..fba9c1f --- /dev/null +++ b/glpk-5.0/src/api/maxflp.c @@ -0,0 +1,112 @@ +/* maxflp.c (convert maximum flow problem to LP) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_maxflow_lp - convert maximum flow problem to LP +* +* SYNOPSIS +* +* void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, +* int t, int a_cap); +* +* DESCRIPTION +* +* The routine glp_maxflow_lp builds an LP problem, which corresponds +* to the maximum flow problem on the specified network G. */ + +void glp_maxflow_lp(glp_prob *lp, glp_graph *G, int names, int s, + int t, int a_cap) +{ glp_vertex *v; + glp_arc *a; + int i, j, type, ind[1+2]; + double cap, val[1+2]; + if (!(names == GLP_ON || names == GLP_OFF)) + xerror("glp_maxflow_lp: names = %d; invalid parameter\n", + names); + if (!(1 <= s && s <= G->nv)) + xerror("glp_maxflow_lp: s = %d; source node number out of rang" + "e\n", s); + if (!(1 <= t && t <= G->nv)) + xerror("glp_maxflow_lp: t = %d: sink node number out of range " + "\n", t); + if (s == t) + xerror("glp_maxflow_lp: s = t = %d; source and sink nodes must" + " be distinct\n", s); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_maxflow_lp: a_cap = %d; invalid offset\n", a_cap); + glp_erase_prob(lp); + if (names) glp_set_prob_name(lp, G->name); + glp_set_obj_dir(lp, GLP_MAX); + glp_add_rows(lp, G->nv); + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (names) glp_set_row_name(lp, i, v->name); + if (i == s) + type = GLP_LO; + else if (i == t) + type = GLP_UP; + else + type = GLP_FX; + glp_set_row_bnds(lp, i, type, 0.0, 0.0); + } + if (G->na > 0) glp_add_cols(lp, G->na); + for (i = 1, j = 0; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { j++; + if (names) + { char name[50+1]; + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); + xassert(strlen(name) < sizeof(name)); + glp_set_col_name(lp, j, name); + } + if (a->tail->i != a->head->i) + { ind[1] = a->tail->i, val[1] = +1.0; + ind[2] = a->head->i, val[2] = -1.0; + glp_set_mat_col(lp, j, 2, ind, val); + } + if (a_cap >= 0) + memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); + else + cap = 1.0; + if (cap == DBL_MAX) + type = GLP_LO; + else if (cap != 0.0) + type = GLP_DB; + else + type = GLP_FX; + glp_set_col_bnds(lp, j, type, 0.0, cap); + if (a->tail->i == s) + glp_set_obj_coef(lp, j, +1.0); + else if (a->head->i == s) + glp_set_obj_coef(lp, j, -1.0); + } + } + xassert(j == G->na); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcflp.c b/glpk-5.0/src/api/mcflp.c new file mode 100644 index 0000000..e4ef0b6 --- /dev/null +++ b/glpk-5.0/src/api/mcflp.c @@ -0,0 +1,112 @@ +/* mcflp.c (convert minimum cost flow problem to LP) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_mincost_lp - convert minimum cost flow problem to LP +* +* SYNOPSIS +* +* void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, +* int v_rhs, int a_low, int a_cap, int a_cost); +* +* DESCRIPTION +* +* The routine glp_mincost_lp builds an LP problem, which corresponds +* to the minimum cost flow problem on the specified network G. */ + +void glp_mincost_lp(glp_prob *lp, glp_graph *G, int names, int v_rhs, + int a_low, int a_cap, int a_cost) +{ glp_vertex *v; + glp_arc *a; + int i, j, type, ind[1+2]; + double rhs, low, cap, cost, val[1+2]; + if (!(names == GLP_ON || names == GLP_OFF)) + xerror("glp_mincost_lp: names = %d; invalid parameter\n", + names); + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) + xerror("glp_mincost_lp: v_rhs = %d; invalid offset\n", v_rhs); + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_lp: a_low = %d; invalid offset\n", a_low); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_lp: a_cap = %d; invalid offset\n", a_cap); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_lp: a_cost = %d; invalid offset\n", a_cost) + ; + glp_erase_prob(lp); + if (names) glp_set_prob_name(lp, G->name); + if (G->nv > 0) glp_add_rows(lp, G->nv); + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (names) glp_set_row_name(lp, i, v->name); + if (v_rhs >= 0) + memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); + else + rhs = 0.0; + glp_set_row_bnds(lp, i, GLP_FX, rhs, rhs); + } + if (G->na > 0) glp_add_cols(lp, G->na); + for (i = 1, j = 0; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { j++; + if (names) + { char name[50+1]; + sprintf(name, "x[%d,%d]", a->tail->i, a->head->i); + xassert(strlen(name) < sizeof(name)); + glp_set_col_name(lp, j, name); + } + if (a->tail->i != a->head->i) + { ind[1] = a->tail->i, val[1] = +1.0; + ind[2] = a->head->i, val[2] = -1.0; + glp_set_mat_col(lp, j, 2, ind, val); + } + if (a_low >= 0) + memcpy(&low, (char *)a->data + a_low, sizeof(double)); + else + low = 0.0; + if (a_cap >= 0) + memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); + else + cap = 1.0; + if (cap == DBL_MAX) + type = GLP_LO; + else if (low != cap) + type = GLP_DB; + else + type = GLP_FX; + glp_set_col_bnds(lp, j, type, low, cap); + if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 0.0; + glp_set_obj_coef(lp, j, cost); + } + } + xassert(j == G->na); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcfokalg.c b/glpk-5.0/src/api/mcfokalg.c new file mode 100644 index 0000000..c2d2794 --- /dev/null +++ b/glpk-5.0/src/api/mcfokalg.c @@ -0,0 +1,219 @@ +/* mcfokalg.c (find minimum-cost flow with out-of-kilter algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "okalg.h" + +int glp_mincost_okalg(glp_graph *G, int v_rhs, int a_low, int a_cap, + int a_cost, double *sol, int a_x, int v_pi) +{ /* find minimum-cost flow with out-of-kilter algorithm */ + glp_vertex *v; + glp_arc *a; + int nv, na, i, k, s, t, *tail, *head, *low, *cap, *cost, *x, *pi, + ret; + double sum, temp; + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: v_rhs = %d; invalid offset\n", + v_rhs); + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: a_low = %d; invalid offset\n", + a_low); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: a_cap = %d; invalid offset\n", + a_cap); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: a_cost = %d; invalid offset\n", + a_cost); + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: a_x = %d; invalid offset\n", a_x); + if (v_pi >= 0 && v_pi > G->v_size - (int)sizeof(double)) + xerror("glp_mincost_okalg: v_pi = %d; invalid offset\n", v_pi); + /* s is artificial source node */ + s = G->nv + 1; + /* t is artificial sink node */ + t = s + 1; + /* nv is the total number of nodes in the resulting network */ + nv = t; + /* na is the total number of arcs in the resulting network */ + na = G->na + 1; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (v_rhs >= 0) + memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); + else + temp = 0.0; + if (temp != 0.0) na++; + } + /* allocate working arrays */ + tail = xcalloc(1+na, sizeof(int)); + head = xcalloc(1+na, sizeof(int)); + low = xcalloc(1+na, sizeof(int)); + cap = xcalloc(1+na, sizeof(int)); + cost = xcalloc(1+na, sizeof(int)); + x = xcalloc(1+na, sizeof(int)); + pi = xcalloc(1+nv, sizeof(int)); + /* construct the resulting network */ + k = 0; + /* (original arcs) */ + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + tail[k] = a->tail->i; + head[k] = a->head->i; + if (tail[k] == head[k]) + { ret = GLP_EDATA; + goto done; + } + if (a_low >= 0) + memcpy(&temp, (char *)a->data + a_low, sizeof(double)); + else + temp = 0.0; + if (!(0.0 <= temp && temp <= (double)INT_MAX && + temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + low[k] = (int)temp; + if (a_cap >= 0) + memcpy(&temp, (char *)a->data + a_cap, sizeof(double)); + else + temp = 1.0; + if (!((double)low[k] <= temp && temp <= (double)INT_MAX && + temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + cap[k] = (int)temp; + if (a_cost >= 0) + memcpy(&temp, (char *)a->data + a_cost, sizeof(double)); + else + temp = 0.0; + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + cost[k] = (int)temp; + } + } + /* (artificial arcs) */ + sum = 0.0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (v_rhs >= 0) + memcpy(&temp, (char *)v->data + v_rhs, sizeof(double)); + else + temp = 0.0; + if (!(fabs(temp) <= (double)INT_MAX && temp == floor(temp))) + { ret = GLP_EDATA; + goto done; + } + if (temp > 0.0) + { /* artificial arc from s to original source i */ + k++; + tail[k] = s; + head[k] = i; + low[k] = cap[k] = (int)(+temp); /* supply */ + cost[k] = 0; + sum += (double)temp; + } + else if (temp < 0.0) + { /* artificial arc from original sink i to t */ + k++; + tail[k] = i; + head[k] = t; + low[k] = cap[k] = (int)(-temp); /* demand */ + cost[k] = 0; + } + } + /* (feedback arc from t to s) */ + k++; + xassert(k == na); + tail[k] = t; + head[k] = s; + if (sum > (double)INT_MAX) + { ret = GLP_EDATA; + goto done; + } + low[k] = cap[k] = (int)sum; /* total supply/demand */ + cost[k] = 0; + /* find minimal-cost circulation in the resulting network */ + ret = okalg(nv, na, tail, head, low, cap, cost, x, pi); + switch (ret) + { case 0: + /* optimal circulation found */ + ret = 0; + break; + case 1: + /* no feasible circulation exists */ + ret = GLP_ENOPFS; + break; + case 2: + /* integer overflow occured */ + ret = GLP_ERANGE; + goto done; + case 3: + /* optimality test failed (logic error) */ + ret = GLP_EFAIL; + goto done; + default: + xassert(ret != ret); + } + /* store solution components */ + /* (objective function = the total cost) */ + if (sol != NULL) + { temp = 0.0; + for (k = 1; k <= na; k++) + temp += (double)cost[k] * (double)x[k]; + *sol = temp; + } + /* (arc flows) */ + if (a_x >= 0) + { k = 0; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { temp = (double)x[++k]; + memcpy((char *)a->data + a_x, &temp, sizeof(double)); + } + } + } + /* (node potentials = Lagrange multipliers) */ + if (v_pi >= 0) + { for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + temp = - (double)pi[i]; + memcpy((char *)v->data + v_pi, &temp, sizeof(double)); + } + } +done: /* free working arrays */ + xfree(tail); + xfree(head); + xfree(low); + xfree(cap); + xfree(cost); + xfree(x); + xfree(pi); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mcfrelax.c b/glpk-5.0/src/api/mcfrelax.c new file mode 100644 index 0000000..74c2826 --- /dev/null +++ b/glpk-5.0/src/api/mcfrelax.c @@ -0,0 +1,249 @@ +/* mcfrelax.c (find minimum-cost flow with RELAX-IV) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2013-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "relax4.h" + +static int overflow(int u, int v) +{ /* check for integer overflow on computing u + v */ + if (u > 0 && v > 0 && u + v < 0) return 1; + if (u < 0 && v < 0 && u + v > 0) return 1; + return 0; +} + +int glp_mincost_relax4(glp_graph *G, int v_rhs, int a_low, int a_cap, + int a_cost, int crash, double *sol, int a_x, int a_rc) +{ /* find minimum-cost flow with Bertsekas-Tseng relaxation method + (RELAX-IV) */ + glp_vertex *v; + glp_arc *a; + struct relax4_csa csa; + int i, k, large, n, na, ret; + double cap, cost, low, rc, rhs, sum, x; + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: v_rhs = %d; invalid offset\n", + v_rhs); + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: a_low = %d; invalid offset\n", + a_low); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: a_cap = %d; invalid offset\n", + a_cap); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: a_cost = %d; invalid offset\n", + a_cost); + if (a_x >= 0 && a_x > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: a_x = %d; invalid offset\n", + a_x); + if (a_rc >= 0 && a_rc > G->a_size - (int)sizeof(double)) + xerror("glp_mincost_relax4: a_rc = %d; invalid offset\n", + a_rc); + csa.n = n = G->nv; /* number of nodes */ + csa.na = na = G->na; /* number of arcs */ + csa.large = large = INT_MAX / 4; + csa.repeat = 0; + csa.crash = crash; + /* allocate working arrays */ + csa.startn = xcalloc(1+na, sizeof(int)); + csa.endn = xcalloc(1+na, sizeof(int)); + csa.fou = xcalloc(1+n, sizeof(int)); + csa.nxtou = xcalloc(1+na, sizeof(int)); + csa.fin = xcalloc(1+n, sizeof(int)); + csa.nxtin = xcalloc(1+na, sizeof(int)); + csa.rc = xcalloc(1+na, sizeof(int)); + csa.u = xcalloc(1+na, sizeof(int)); + csa.dfct = xcalloc(1+n, sizeof(int)); + csa.x = xcalloc(1+na, sizeof(int)); + csa.label = xcalloc(1+n, sizeof(int)); + csa.prdcsr = xcalloc(1+n, sizeof(int)); + csa.save = xcalloc(1+na, sizeof(int)); + csa.tfstou = xcalloc(1+n, sizeof(int)); + csa.tnxtou = xcalloc(1+na, sizeof(int)); + csa.tfstin = xcalloc(1+n, sizeof(int)); + csa.tnxtin = xcalloc(1+na, sizeof(int)); + csa.nxtqueue = xcalloc(1+n, sizeof(int)); + csa.scan = xcalloc(1+n, sizeof(char)); + csa.mark = xcalloc(1+n, sizeof(char)); + if (crash) + { csa.extend_arc = xcalloc(1+n, sizeof(int)); + csa.sb_level = xcalloc(1+n, sizeof(int)); + csa.sb_arc = xcalloc(1+n, sizeof(int)); + } + else + { csa.extend_arc = NULL; + csa.sb_level = NULL; + csa.sb_arc = NULL; + } + /* scan nodes */ + for (i = 1; i <= n; i++) + { v = G->v[i]; + /* get supply at i-th node */ + if (v_rhs >= 0) + memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); + else + rhs = 0.0; + if (!(fabs(rhs) <= (double)large && rhs == floor(rhs))) + { ret = GLP_EDATA; + goto done; + } + /* set demand at i-th node */ + csa.dfct[i] = -(int)rhs; + } + /* scan arcs */ + k = 0; + for (i = 1; i <= n; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + /* set endpoints of k-th arc */ + if (a->tail->i == a->head->i) + { /* self-loops not allowed */ + ret = GLP_EDATA; + goto done; + } + csa.startn[k] = a->tail->i; + csa.endn[k] = a->head->i; + /* set per-unit cost for k-th arc flow */ + if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 0.0; + if (!(fabs(cost) <= (double)large && cost == floor(cost))) + { ret = GLP_EDATA; + goto done; + } + csa.rc[k] = (int)cost; + /* get lower bound for k-th arc flow */ + if (a_low >= 0) + memcpy(&low, (char *)a->data + a_low, sizeof(double)); + else + low = 0.0; + if (!(0.0 <= low && low <= (double)large && + low == floor(low))) + { ret = GLP_EDATA; + goto done; + } + /* get upper bound for k-th arc flow */ + if (a_cap >= 0) + memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); + else + cap = 1.0; + if (!(low <= cap && cap <= (double)large && + cap == floor(cap))) + { ret = GLP_EDATA; + goto done; + } + /* substitute x = x' + low, where 0 <= x' <= cap - low */ + csa.u[k] = (int)(cap - low); + /* correct demands at endpoints of k-th arc */ + if (overflow(csa.dfct[a->tail->i], +low)) + { ret = GLP_ERANGE; + goto done; + } +#if 0 /* 29/IX-2017 */ + csa.dfct[a->tail->i] += low; +#else + csa.dfct[a->tail->i] += (int)low; +#endif + if (overflow(csa.dfct[a->head->i], -low)) + { ret = GLP_ERANGE; + goto done; + } +#if 0 /* 29/IX-2017 */ + csa.dfct[a->head->i] -= low; +#else + csa.dfct[a->head->i] -= (int)low; +#endif + } + } + /* construct linked list for network topology */ + relax4_inidat(&csa); + /* find minimum-cost flow */ + ret = relax4(&csa); + if (ret != 0) + { /* problem is found to be infeasible */ + xassert(1 <= ret && ret <= 8); + ret = GLP_ENOPFS; + goto done; + } + /* store solution */ + sum = 0.0; + k = 0; + for (i = 1; i <= n; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { k++; + /* get lower bound for k-th arc flow */ + if (a_low >= 0) + memcpy(&low, (char *)a->data + a_low, sizeof(double)); + else + low = 0.0; + /* store original flow x = x' + low thru k-th arc */ + x = (double)csa.x[k] + low; + if (a_x >= 0) + memcpy((char *)a->data + a_x, &x, sizeof(double)); + /* store reduced cost for k-th arc flow */ + rc = (double)csa.rc[k]; + if (a_rc >= 0) + memcpy((char *)a->data + a_rc, &rc, sizeof(double)); + /* get per-unit cost for k-th arc flow */ + if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 0.0; + /* compute the total cost */ + sum += cost * x; + } + } + /* store the total cost */ + if (sol != NULL) + *sol = sum; +done: /* free working arrays */ + xfree(csa.startn); + xfree(csa.endn); + xfree(csa.fou); + xfree(csa.nxtou); + xfree(csa.fin); + xfree(csa.nxtin); + xfree(csa.rc); + xfree(csa.u); + xfree(csa.dfct); + xfree(csa.x); + xfree(csa.label); + xfree(csa.prdcsr); + xfree(csa.save); + xfree(csa.tfstou); + xfree(csa.tnxtou); + xfree(csa.tfstin); + xfree(csa.tnxtin); + xfree(csa.nxtqueue); + xfree(csa.scan); + xfree(csa.mark); + if (crash) + { xfree(csa.extend_arc); + xfree(csa.sb_level); + xfree(csa.sb_arc); + } + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/minisat1.c b/glpk-5.0/src/api/minisat1.c new file mode 100644 index 0000000..6015760 --- /dev/null +++ b/glpk-5.0/src/api/minisat1.c @@ -0,0 +1,159 @@ +/* minisat1.c (driver to MiniSat solver) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2011-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "minisat.h" +#include "prob.h" + +int glp_minisat1(glp_prob *P) +{ /* solve CNF-SAT problem with MiniSat solver */ + solver *s; + GLPAIJ *aij; + int i, j, len, ret, *ind; + double sum; +#if 0 /* 04/IV-2016 */ + /* check problem object */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_minisat1: P = %p; invalid problem object\n", + P); +#endif + if (P->tree != NULL) + xerror("glp_minisat1: operation not allowed\n"); + /* integer solution is currently undefined */ + P->mip_stat = GLP_UNDEF; + P->mip_obj = 0.0; + /* check that problem object encodes CNF-SAT instance */ + if (glp_check_cnfsat(P) != 0) + { xprintf("glp_minisat1: problem object does not encode CNF-SAT " + "instance\n"); + ret = GLP_EDATA; + goto done; + } +#if 0 /* 08/I-2017 by cmatraki */ +#if 1 /* 07/XI-2015 */ + if (sizeof(void *) != sizeof(int)) + { xprintf("glp_minisat1: sorry, MiniSat solver is not supported " + "on 64-bit platforms\n"); + ret = GLP_EFAIL; + goto done; + } +#endif +#else + if (sizeof(void *) != sizeof(size_t)) + { xprintf("glp_minisat1: sorry, MiniSat solver is not supported " + "on this platform\n"); + ret = GLP_EFAIL; + goto done; + } +#endif + /* solve CNF-SAT problem */ + xprintf("Solving CNF-SAT problem...\n"); + xprintf("Instance has %d variable%s, %d clause%s, and %d literal%" + "s\n", P->n, P->n == 1 ? "" : "s", P->m, P->m == 1 ? "" : "s", + P->nnz, P->nnz == 1 ? "" : "s"); + /* if CNF-SAT has no clauses, it is satisfiable */ + if (P->m == 0) + { P->mip_stat = GLP_OPT; + for (j = 1; j <= P->n; j++) + P->col[j]->mipx = 0.0; + goto fini; + } + /* if CNF-SAT has an empty clause, it is unsatisfiable */ + for (i = 1; i <= P->m; i++) + { if (P->row[i]->ptr == NULL) + { P->mip_stat = GLP_NOFEAS; + goto fini; + } + } + /* prepare input data for the solver */ + s = solver_new(); + solver_setnvars(s, P->n); + ind = xcalloc(1+P->n, sizeof(int)); + for (i = 1; i <= P->m; i++) + { len = 0; + for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) + { ind[++len] = toLit(aij->col->j-1); + if (aij->val < 0.0) + ind[len] = lit_neg(ind[len]); + } + xassert(len > 0); +#if 0 /* 08/I-2017 by cmatraki */ + xassert(solver_addclause(s, &ind[1], &ind[1+len])); +#else + if (!solver_addclause(s, &ind[1], &ind[1+len])) + { /* found trivial conflict */ + xfree(ind); + solver_delete(s); + P->mip_stat = GLP_NOFEAS; + goto fini; + } +#endif + } + xfree(ind); + /* call the solver */ + s->verbosity = 1; + if (solver_solve(s, 0, 0)) + { /* instance is reported as satisfiable */ + P->mip_stat = GLP_OPT; + /* copy solution to the problem object */ + xassert(s->model.size == P->n); + for (j = 1; j <= P->n; j++) + { P->col[j]->mipx = + s->model.ptr[j-1] == l_True ? 1.0 : 0.0; + } + /* compute row values */ + for (i = 1; i <= P->m; i++) + { sum = 0; + for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) + sum += aij->val * aij->col->mipx; + P->row[i]->mipx = sum; + } + /* check integer feasibility */ + for (i = 1; i <= P->m; i++) + { if (P->row[i]->mipx < P->row[i]->lb) + { /* solution is wrong */ + P->mip_stat = GLP_UNDEF; + break; + } + } + } + else + { /* instance is reported as unsatisfiable */ + P->mip_stat = GLP_NOFEAS; + } + solver_delete(s); +fini: /* report the instance status */ + if (P->mip_stat == GLP_OPT) + { xprintf("SATISFIABLE\n"); + ret = 0; + } + else if (P->mip_stat == GLP_NOFEAS) + { xprintf("UNSATISFIABLE\n"); + ret = 0; + } + else + { xprintf("glp_minisat1: solver failed\n"); + ret = GLP_EFAIL; + } +done: return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mpl.c b/glpk-5.0/src/api/mpl.c new file mode 100644 index 0000000..6dd886c --- /dev/null +++ b/glpk-5.0/src/api/mpl.c @@ -0,0 +1,267 @@ +/* mpl.c (processing model in GNU MathProg language) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2008-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "mpl.h" +#include "prob.h" + +glp_tran *glp_mpl_alloc_wksp(void) +{ /* allocate the MathProg translator workspace */ + glp_tran *tran; + tran = mpl_initialize(); + return tran; +} + +void glp_mpl_init_rand(glp_tran *tran, int seed) +{ /* initialize pseudo-random number generator */ + if (tran->phase != 0) + xerror("glp_mpl_init_rand: invalid call sequence\n"); + rng_init_rand(tran->rand, seed); + return; +} + +int glp_mpl_read_model(glp_tran *tran, const char *fname, int skip) +{ /* read and translate model section */ + int ret; + if (tran->phase != 0) + xerror("glp_mpl_read_model: invalid call sequence\n"); + ret = mpl_read_model(tran, (char *)fname, skip); + if (ret == 1 || ret == 2) + ret = 0; + else if (ret == 4) + ret = 1; + else + xassert(ret != ret); + return ret; +} + +int glp_mpl_read_data(glp_tran *tran, const char *fname) +{ /* read and translate data section */ + int ret; + if (!(tran->phase == 1 || tran->phase == 2)) + xerror("glp_mpl_read_data: invalid call sequence\n"); + ret = mpl_read_data(tran, (char *)fname); + if (ret == 2) + ret = 0; + else if (ret == 4) + ret = 1; + else + xassert(ret != ret); + return ret; +} + +int glp_mpl_generate(glp_tran *tran, const char *fname) +{ /* generate the model */ + int ret; + if (!(tran->phase == 1 || tran->phase == 2)) + xerror("glp_mpl_generate: invalid call sequence\n"); + ret = mpl_generate(tran, (char *)fname); + if (ret == 3) + ret = 0; + else if (ret == 4) + ret = 1; + return ret; +} + +void glp_mpl_build_prob(glp_tran *tran, glp_prob *prob) +{ /* build LP/MIP problem instance from the model */ + int m, n, i, j, t, kind, type, len, *ind; + double lb, ub, *val; + if (tran->phase != 3) + xerror("glp_mpl_build_prob: invalid call sequence\n"); + /* erase the problem object */ + glp_erase_prob(prob); + /* set problem name */ + glp_set_prob_name(prob, mpl_get_prob_name(tran)); + /* build rows (constraints) */ + m = mpl_get_num_rows(tran); + if (m > 0) + glp_add_rows(prob, m); + for (i = 1; i <= m; i++) + { /* set row name */ + glp_set_row_name(prob, i, mpl_get_row_name(tran, i)); + /* set row bounds */ + type = mpl_get_row_bnds(tran, i, &lb, &ub); + switch (type) + { case MPL_FR: type = GLP_FR; break; + case MPL_LO: type = GLP_LO; break; + case MPL_UP: type = GLP_UP; break; + case MPL_DB: type = GLP_DB; break; + case MPL_FX: type = GLP_FX; break; + default: xassert(type != type); + } + if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) + { type = GLP_FX; + if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; + } + glp_set_row_bnds(prob, i, type, lb, ub); + /* warn about non-zero constant term */ + if (mpl_get_row_c0(tran, i) != 0.0) + xprintf("glp_mpl_build_prob: row %s; constant term %.12g ig" + "nored\n", + mpl_get_row_name(tran, i), mpl_get_row_c0(tran, i)); + } + /* build columns (variables) */ + n = mpl_get_num_cols(tran); + if (n > 0) + glp_add_cols(prob, n); + for (j = 1; j <= n; j++) + { /* set column name */ + glp_set_col_name(prob, j, mpl_get_col_name(tran, j)); + /* set column kind */ + kind = mpl_get_col_kind(tran, j); + switch (kind) + { case MPL_NUM: + break; + case MPL_INT: + case MPL_BIN: + glp_set_col_kind(prob, j, GLP_IV); + break; + default: + xassert(kind != kind); + } + /* set column bounds */ + type = mpl_get_col_bnds(tran, j, &lb, &ub); + switch (type) + { case MPL_FR: type = GLP_FR; break; + case MPL_LO: type = GLP_LO; break; + case MPL_UP: type = GLP_UP; break; + case MPL_DB: type = GLP_DB; break; + case MPL_FX: type = GLP_FX; break; + default: xassert(type != type); + } + if (kind == MPL_BIN) + { if (type == GLP_FR || type == GLP_UP || lb < 0.0) lb = 0.0; + if (type == GLP_FR || type == GLP_LO || ub > 1.0) ub = 1.0; + type = GLP_DB; + } + if (type == GLP_DB && fabs(lb - ub) < 1e-9 * (1.0 + fabs(lb))) + { type = GLP_FX; + if (fabs(lb) <= fabs(ub)) ub = lb; else lb = ub; + } + glp_set_col_bnds(prob, j, type, lb, ub); + } + /* load the constraint matrix */ + ind = xcalloc(1+n, sizeof(int)); + val = xcalloc(1+n, sizeof(double)); + for (i = 1; i <= m; i++) + { len = mpl_get_mat_row(tran, i, ind, val); + glp_set_mat_row(prob, i, len, ind, val); + } + /* build objective function (the first objective is used) */ + for (i = 1; i <= m; i++) + { kind = mpl_get_row_kind(tran, i); + if (kind == MPL_MIN || kind == MPL_MAX) + { /* set objective name */ + glp_set_obj_name(prob, mpl_get_row_name(tran, i)); + /* set optimization direction */ + glp_set_obj_dir(prob, kind == MPL_MIN ? GLP_MIN : GLP_MAX); + /* set constant term */ + glp_set_obj_coef(prob, 0, mpl_get_row_c0(tran, i)); + /* set objective coefficients */ + len = mpl_get_mat_row(tran, i, ind, val); + for (t = 1; t <= len; t++) + glp_set_obj_coef(prob, ind[t], val[t]); + break; + } + } + /* free working arrays */ + xfree(ind); + xfree(val); + return; +} + +int glp_mpl_postsolve(glp_tran *tran, glp_prob *prob, int sol) +{ /* postsolve the model */ + int i, j, m, n, stat, ret; + double prim, dual; + if (!(tran->phase == 3 && !tran->flag_p)) + xerror("glp_mpl_postsolve: invalid call sequence\n"); + if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) + xerror("glp_mpl_postsolve: sol = %d; invalid parameter\n", + sol); + m = mpl_get_num_rows(tran); + n = mpl_get_num_cols(tran); + if (!(m == glp_get_num_rows(prob) && + n == glp_get_num_cols(prob))) + xerror("glp_mpl_postsolve: wrong problem object\n"); + if (!mpl_has_solve_stmt(tran)) + { ret = 0; + goto done; + } + for (i = 1; i <= m; i++) + { if (sol == GLP_SOL) + { stat = glp_get_row_stat(prob, i); + prim = glp_get_row_prim(prob, i); + dual = glp_get_row_dual(prob, i); + } + else if (sol == GLP_IPT) + { stat = 0; + prim = glp_ipt_row_prim(prob, i); + dual = glp_ipt_row_dual(prob, i); + } + else if (sol == GLP_MIP) + { stat = 0; + prim = glp_mip_row_val(prob, i); + dual = 0.0; + } + else + xassert(sol != sol); + if (fabs(prim) < 1e-9) prim = 0.0; + if (fabs(dual) < 1e-9) dual = 0.0; + mpl_put_row_soln(tran, i, stat, prim, dual); + } + for (j = 1; j <= n; j++) + { if (sol == GLP_SOL) + { stat = glp_get_col_stat(prob, j); + prim = glp_get_col_prim(prob, j); + dual = glp_get_col_dual(prob, j); + } + else if (sol == GLP_IPT) + { stat = 0; + prim = glp_ipt_col_prim(prob, j); + dual = glp_ipt_col_dual(prob, j); + } + else if (sol == GLP_MIP) + { stat = 0; + prim = glp_mip_col_val(prob, j); + dual = 0.0; + } + else + xassert(sol != sol); + if (fabs(prim) < 1e-9) prim = 0.0; + if (fabs(dual) < 1e-9) dual = 0.0; + mpl_put_col_soln(tran, j, stat, prim, dual); + } + ret = mpl_postsolve(tran); + if (ret == 3) + ret = 0; + else if (ret == 4) + ret = 1; +done: return ret; +} + +void glp_mpl_free_wksp(glp_tran *tran) +{ /* free the MathProg translator workspace */ + mpl_terminate(tran); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/mps.c b/glpk-5.0/src/api/mps.c new file mode 100644 index 0000000..c17d8d9 --- /dev/null +++ b/glpk-5.0/src/api/mps.c @@ -0,0 +1,1450 @@ +/* mps.c (MPS format routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2008-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_init_mpscp - initialize MPS format control parameters +* +* SYNOPSIS +* +* void glp_init_mpscp(glp_mpscp *parm); +* +* DESCRIPTION +* +* The routine glp_init_mpscp initializes control parameters, which are +* used by the MPS input/output routines glp_read_mps and glp_write_mps, +* with default values. +* +* Default values of the control parameters are stored in the glp_mpscp +* structure, which the parameter parm points to. */ + +void glp_init_mpscp(glp_mpscp *parm) +{ parm->blank = '\0'; + parm->obj_name = NULL; + parm->tol_mps = 1e-12; + return; +} + +static void check_parm(const char *func, const glp_mpscp *parm) +{ /* check control parameters */ + if (!(0x00 <= parm->blank && parm->blank <= 0xFF) || + !(parm->blank == '\0' || isprint(parm->blank))) + xerror("%s: blank = 0x%02X; invalid parameter\n", + func, parm->blank); + if (!(parm->obj_name == NULL || strlen(parm->obj_name) <= 255)) + xerror("%s: obj_name = \"%.12s...\"; parameter too long\n", + func, parm->obj_name); + if (!(0.0 <= parm->tol_mps && parm->tol_mps < 1.0)) + xerror("%s: tol_mps = %g; invalid parameter\n", + func, parm->tol_mps); + return; +} + +/*********************************************************************** +* NAME +* +* glp_read_mps - read problem data in MPS format +* +* SYNOPSIS +* +* int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_mps reads problem data in MPS format from a +* text file. +* +* The parameter fmt specifies the version of MPS format: +* +* GLP_MPS_DECK - fixed (ancient) MPS format; +* GLP_MPS_FILE - free (modern) MPS format. +* +* The parameter parm is a pointer to the structure glp_mpscp, which +* specifies control parameters used by the routine. If parm is NULL, +* the routine uses default settings. +* +* The character string fname specifies a name of the text file to be +* read. +* +* Note that before reading data the current content of the problem +* object is completely erased with the routine glp_erase_prob. +* +* RETURNS +* +* If the operation was successful, the routine glp_read_mps returns +* zero. Otherwise, it prints an error message and returns non-zero. */ + +struct csa +{ /* common storage area */ + glp_prob *P; + /* pointer to problem object */ + int deck; + /* MPS format (0 - free, 1 - fixed) */ + const glp_mpscp *parm; + /* pointer to control parameters */ + const char *fname; + /* name of input MPS file */ + glp_file *fp; + /* stream assigned to input MPS file */ + jmp_buf jump; + /* label for go to in case of error */ + int recno; + /* current record (card) number */ + int recpos; + /* current record (card) position */ + int c; + /* current character */ + int fldno; + /* current field number */ + char field[255+1]; + /* current field content */ + int w80; + /* warning 'record must not be longer than 80 chars' issued */ + int wef; + /* warning 'extra fields detected beyond field 6' issued */ + int obj_row; + /* objective row number */ + void *work1, *work2, *work3; + /* working arrays */ +}; + +static void error(struct csa *csa, const char *fmt, ...) +{ /* print error message and terminate processing */ + va_list arg; + xprintf("%s:%d: ", csa->fname, csa->recno); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + longjmp(csa->jump, 1); + /* no return */ +} + +static void warning(struct csa *csa, const char *fmt, ...) +{ /* print warning message and continue processing */ + va_list arg; + xprintf("%s:%d: warning: ", csa->fname, csa->recno); + va_start(arg, fmt); + xvprintf(fmt, arg); + va_end(arg); + return; +} + +static void read_char(struct csa *csa) +{ /* read next character */ + int c; + if (csa->c == '\n') + csa->recno++, csa->recpos = 0; + csa->recpos++; +read: c = glp_getc(csa->fp); + if (c < 0) + { if (glp_ioerr(csa->fp)) + error(csa, "read error - %s\n", get_err_msg()); + else if (csa->c == '\n') + error(csa, "unexpected end of file\n"); + else + { warning(csa, "missing final end of line\n"); + c = '\n'; + } + } + else if (c == '\n') + ; + else if (csa->c == '\r') + { c = '\r'; + goto badc; + } + else if (csa->deck && c == '\r') + { csa->c = '\r'; + goto read; + } + else if (c == ' ') + ; + else if (isspace(c)) + { if (csa->deck) +badc: error(csa, "in fixed MPS format white-space character 0x%02" + "X is not allowed\n", c); + c = ' '; + } + else if (iscntrl(c)) + error(csa, "invalid control character 0x%02X\n", c); + if (csa->deck && csa->recpos == 81 && c != '\n' && csa->w80 < 1) + { warning(csa, "in fixed MPS format record must not be longer th" + "an 80 characters\n"); + csa->w80++; + } + csa->c = c; + return; +} + +static int indicator(struct csa *csa, int name) +{ /* skip comment records and read possible indicator record */ + int ret; + /* reset current field number */ + csa->fldno = 0; +loop: /* read the very first character of the next record */ + xassert(csa->c == '\n'); + read_char(csa); + if (csa->c == ' ' || csa->c == '\n') + { /* data record */ + ret = 0; + } + else if (csa->c == '*') + { /* comment record */ + while (csa->c != '\n') + read_char(csa); + goto loop; + } + else + { /* indicator record */ + int len = 0; + while (csa->c != ' ' && csa->c != '\n' && len < 12) + { csa->field[len++] = (char)csa->c; + read_char(csa); + } + csa->field[len] = '\0'; + if (!(strcmp(csa->field, "NAME") == 0 || + strcmp(csa->field, "ROWS") == 0 || + strcmp(csa->field, "COLUMNS") == 0 || + strcmp(csa->field, "RHS") == 0 || + strcmp(csa->field, "RANGES") == 0 || + strcmp(csa->field, "BOUNDS") == 0 || + strcmp(csa->field, "ENDATA") == 0)) + error(csa, "invalid indicator record\n"); + if (!name) + { while (csa->c != '\n') + read_char(csa); + } + ret = 1; + } + return ret; +} + +static void read_field(struct csa *csa) +{ /* read next field of the current data record */ + csa->fldno++; + if (csa->deck) + { /* fixed MPS format */ + int beg, end, pos; + /* determine predefined field positions */ + if (csa->fldno == 1) + beg = 2, end = 3; + else if (csa->fldno == 2) + beg = 5, end = 12; + else if (csa->fldno == 3) + beg = 15, end = 22; + else if (csa->fldno == 4) + beg = 25, end = 36; + else if (csa->fldno == 5) + beg = 40, end = 47; + else if (csa->fldno == 6) + beg = 50, end = 61; + else + xassert(csa != csa); + /* skip blanks preceding the current field */ + if (csa->c != '\n') + { pos = csa->recpos; + while (csa->recpos < beg) + { if (csa->c == ' ') + ; + else if (csa->c == '\n') + break; + else + error(csa, "in fixed MPS format positions %d-%d must " + "be blank\n", pos, beg-1); + read_char(csa); + } + } + /* skip possible comment beginning in the field 3 or 5 */ + if ((csa->fldno == 3 || csa->fldno == 5) && csa->c == '$') + { while (csa->c != '\n') + read_char(csa); + } + /* read the current field */ + for (pos = beg; pos <= end; pos++) + { if (csa->c == '\n') break; + csa->field[pos-beg] = (char)csa->c; + read_char(csa); + } + csa->field[pos-beg] = '\0'; + strtrim(csa->field); + /* skip blanks following the last field */ + if (csa->fldno == 6 && csa->c != '\n') + { while (csa->recpos <= 72) + { if (csa->c == ' ') + ; + else if (csa->c == '\n') + break; + else + error(csa, "in fixed MPS format positions 62-72 must " + "be blank\n"); + read_char(csa); + } + while (csa->c != '\n') + read_char(csa); + } + } + else + { /* free MPS format */ + int len; + /* skip blanks preceding the current field */ + while (csa->c == ' ') + read_char(csa); + /* skip possible comment */ + if (csa->c == '$') + { while (csa->c != '\n') + read_char(csa); + } + /* read the current field */ + len = 0; + while (!(csa->c == ' ' || csa->c == '\n')) + { if (len == 255) + error(csa, "length of field %d exceeds 255 characters\n", + csa->fldno++); + csa->field[len++] = (char)csa->c; + read_char(csa); + } + csa->field[len] = '\0'; + /* skip anything following the last field (any extra fields + are considered to be comments) */ + if (csa->fldno == 6) + { while (csa->c == ' ') + read_char(csa); + if (csa->c != '$' && csa->c != '\n' && csa->wef < 1) + { warning(csa, "some extra field(s) detected beyond field " + "6; field(s) ignored\n"); + csa->wef++; + } + while (csa->c != '\n') + read_char(csa); + } + } + return; +} + +static void patch_name(struct csa *csa, char *name) +{ /* process embedded blanks in symbolic name */ + int blank = csa->parm->blank; + if (blank == '\0') + { /* remove emedded blanks */ + strspx(name); + } + else + { /* replace embedded blanks by specified character */ + for (; *name != '\0'; name++) + if (*name == ' ') *name = (char)blank; + } + return; +} + +static double read_number(struct csa *csa) +{ /* read next field and convert it to floating-point number */ + double x; + char *s; + /* read next field */ + read_field(csa); + xassert(csa->fldno == 4 || csa->fldno == 6); + if (csa->field[0] == '\0') + error(csa, "missing numeric value in field %d\n", csa->fldno); + /* skip initial spaces of the field */ + for (s = csa->field; *s == ' '; s++); + /* perform conversion */ + if (str2num(s, &x) != 0) + error(csa, "cannot convert '%s' to floating-point number\n", + s); + return x; +} + +static void skip_field(struct csa *csa) +{ /* read and skip next field (assumed to be blank) */ + read_field(csa); + if (csa->field[0] != '\0') + error(csa, "field %d must be blank\n", csa->fldno); + return; +} + +static void read_name(struct csa *csa) +{ /* read NAME indicator record */ + if (!(indicator(csa, 1) && strcmp(csa->field, "NAME") == 0)) + error(csa, "missing NAME indicator record\n"); + /* this indicator record looks like a data record; simulate that + fields 1 and 2 were read */ + csa->fldno = 2; + /* field 3: model name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + warning(csa, "missing model name in field 3\n"); + else + glp_set_prob_name(csa->P, csa->field); + /* skip anything following field 3 */ + while (csa->c != '\n') + read_char(csa); + return; +} + +static void read_rows(struct csa *csa) +{ /* read ROWS section */ + int i, type; +loop: if (indicator(csa, 0)) goto done; + /* field 1: row type */ + read_field(csa), strspx(csa->field); + if (strcmp(csa->field, "N") == 0) + type = GLP_FR; + else if (strcmp(csa->field, "G") == 0) + type = GLP_LO; + else if (strcmp(csa->field, "L") == 0) + type = GLP_UP; + else if (strcmp(csa->field, "E") == 0) + type = GLP_FX; + else if (csa->field[0] == '\0') + error(csa, "missing row type in field 1\n"); + else + error(csa, "invalid row type in field 1\n"); + /* field 2: row name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + error(csa, "missing row name in field 2\n"); + if (glp_find_row(csa->P, csa->field) != 0) + error(csa, "row '%s' multiply specified\n", csa->field); + i = glp_add_rows(csa->P, 1); + glp_set_row_name(csa->P, i, csa->field); + glp_set_row_bnds(csa->P, i, type, 0.0, 0.0); + /* fields 3, 4, 5, and 6 must be blank */ + skip_field(csa); + skip_field(csa); + skip_field(csa); + skip_field(csa); + goto loop; +done: return; +} + +static void read_columns(struct csa *csa) +{ /* read COLUMNS section */ + int i, j, f, len, kind = GLP_CV, *ind; + double aij, *val; + char name[255+1], *flag; + /* allocate working arrays */ + csa->work1 = ind = xcalloc(1+csa->P->m, sizeof(int)); + csa->work2 = val = xcalloc(1+csa->P->m, sizeof(double)); + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); + memset(&flag[1], 0, csa->P->m); + /* no current column exists */ + j = 0, len = 0; +loop: if (indicator(csa, 0)) goto done; + /* field 1 must be blank */ + if (csa->deck) + { read_field(csa); + if (csa->field[0] != '\0') + error(csa, "field 1 must be blank\n"); + } + else + csa->fldno++; + /* field 2: column or kind name */ + read_field(csa), patch_name(csa, csa->field); + strcpy(name, csa->field); + /* field 3: row name or keyword 'MARKER' */ + read_field(csa), patch_name(csa, csa->field); + if (strcmp(csa->field, "'MARKER'") == 0) + { /* process kind data record */ + /* field 4 must be blank */ + if (csa->deck) + { read_field(csa); + if (csa->field[0] != '\0') + error(csa, "field 4 must be blank\n"); + } + else + csa->fldno++; + /* field 5: keyword 'INTORG' or 'INTEND' */ + read_field(csa), patch_name(csa, csa->field); + if (strcmp(csa->field, "'INTORG'") == 0) + kind = GLP_IV; + else if (strcmp(csa->field, "'INTEND'") == 0) + kind = GLP_CV; + else if (csa->field[0] == '\0') + error(csa, "missing keyword in field 5\n"); + else + error(csa, "invalid keyword in field 5\n"); + /* field 6 must be blank */ + skip_field(csa); + goto loop; + } + /* process column name specified in field 2 */ + if (name[0] == '\0') + { /* the same column as in previous data record */ + if (j == 0) + error(csa, "missing column name in field 2\n"); + } + else if (j != 0 && strcmp(name, csa->P->col[j]->name) == 0) + { /* the same column as in previous data record */ + xassert(j != 0); + } + else + { /* store the current column */ + if (j != 0) + { glp_set_mat_col(csa->P, j, len, ind, val); + while (len > 0) flag[ind[len--]] = 0; + } + /* create new column */ + if (glp_find_col(csa->P, name) != 0) + error(csa, "column '%s' multiply specified\n", name); + j = glp_add_cols(csa->P, 1); + glp_set_col_name(csa->P, j, name); + glp_set_col_kind(csa->P, j, kind); + if (kind == GLP_CV) + glp_set_col_bnds(csa->P, j, GLP_LO, 0.0, 0.0); + else if (kind == GLP_IV) + glp_set_col_bnds(csa->P, j, GLP_DB, 0.0, 1.0); + else + xassert(kind != kind); + } + /* process fields 3-4 and 5-6 */ + for (f = 3; f <= 5; f += 2) + { /* field 3 or 5: row name */ + if (f == 3) + { if (csa->field[0] == '\0') + error(csa, "missing row name in field 3\n"); + } + else + { read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { /* if field 5 is blank, field 6 also must be blank */ + skip_field(csa); + continue; + } + } + i = glp_find_row(csa->P, csa->field); + if (i == 0) + error(csa, "row '%s' not found\n", csa->field); + if (flag[i]) + error(csa, "duplicate coefficient in row '%s'\n", + csa->field); + /* field 4 or 6: coefficient value */ + aij = read_number(csa); + if (fabs(aij) < csa->parm->tol_mps) aij = 0.0; + len++, ind[len] = i, val[len] = aij, flag[i] = 1; + } + goto loop; +done: /* store the last column */ + if (j != 0) + glp_set_mat_col(csa->P, j, len, ind, val); + /* free working arrays */ + xfree(ind); + xfree(val); + xfree(flag); + csa->work1 = csa->work2 = csa->work3 = NULL; + return; +} + +static void read_rhs(struct csa *csa) +{ /* read RHS section */ + int i, f, v, type; + double rhs; + char name[255+1], *flag; + /* allocate working array */ + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); + memset(&flag[1], 0, csa->P->m); + /* no current RHS vector exists */ + v = 0; +loop: if (indicator(csa, 0)) goto done; + /* field 1 must be blank */ + if (csa->deck) + { read_field(csa); + if (csa->field[0] != '\0') + error(csa, "field 1 must be blank\n"); + } + else + csa->fldno++; + /* field 2: RHS vector name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { /* the same RHS vector as in previous data record */ + if (v == 0) + { warning(csa, "missing RHS vector name in field 2\n"); + goto blnk; + } + } + else if (v != 0 && strcmp(csa->field, name) == 0) + { /* the same RHS vector as in previous data record */ + xassert(v != 0); + } + else +blnk: { /* new RHS vector */ + if (v != 0) + error(csa, "multiple RHS vectors not supported\n"); + v++; + strcpy(name, csa->field); + } + /* process fields 3-4 and 5-6 */ + for (f = 3; f <= 5; f += 2) + { /* field 3 or 5: row name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { if (f == 3) + error(csa, "missing row name in field 3\n"); + else + { /* if field 5 is blank, field 6 also must be blank */ + skip_field(csa); + continue; + } + } + i = glp_find_row(csa->P, csa->field); + if (i == 0) + error(csa, "row '%s' not found\n", csa->field); + if (flag[i]) + error(csa, "duplicate right-hand side for row '%s'\n", + csa->field); + /* field 4 or 6: right-hand side value */ + rhs = read_number(csa); + if (fabs(rhs) < csa->parm->tol_mps) rhs = 0.0; + type = csa->P->row[i]->type; + if (type == GLP_FR) + { if (i == csa->obj_row) + glp_set_obj_coef(csa->P, 0, rhs); + else if (rhs != 0.0) + warning(csa, "non-zero right-hand side for free row '%s'" + " ignored\n", csa->P->row[i]->name); + } + else + glp_set_row_bnds(csa->P, i, type, rhs, rhs); + flag[i] = 1; + } + goto loop; +done: /* free working array */ + xfree(flag); + csa->work3 = NULL; + return; +} + +static void read_ranges(struct csa *csa) +{ /* read RANGES section */ + int i, f, v, type; + double rhs, rng; + char name[255+1], *flag; + /* allocate working array */ + csa->work3 = flag = xcalloc(1+csa->P->m, sizeof(char)); + memset(&flag[1], 0, csa->P->m); + /* no current RANGES vector exists */ + v = 0; +loop: if (indicator(csa, 0)) goto done; + /* field 1 must be blank */ + if (csa->deck) + { read_field(csa); + if (csa->field[0] != '\0') + error(csa, "field 1 must be blank\n"); + } + else + csa->fldno++; + /* field 2: RANGES vector name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { /* the same RANGES vector as in previous data record */ + if (v == 0) + { warning(csa, "missing RANGES vector name in field 2\n"); + goto blnk; + } + } + else if (v != 0 && strcmp(csa->field, name) == 0) + { /* the same RANGES vector as in previous data record */ + xassert(v != 0); + } + else +blnk: { /* new RANGES vector */ + if (v != 0) + error(csa, "multiple RANGES vectors not supported\n"); + v++; + strcpy(name, csa->field); + } + /* process fields 3-4 and 5-6 */ + for (f = 3; f <= 5; f += 2) + { /* field 3 or 5: row name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { if (f == 3) + error(csa, "missing row name in field 3\n"); + else + { /* if field 5 is blank, field 6 also must be blank */ + skip_field(csa); + continue; + } + } + i = glp_find_row(csa->P, csa->field); + if (i == 0) + error(csa, "row '%s' not found\n", csa->field); + if (flag[i]) + error(csa, "duplicate range for row '%s'\n", csa->field); + /* field 4 or 6: range value */ + rng = read_number(csa); + if (fabs(rng) < csa->parm->tol_mps) rng = 0.0; + type = csa->P->row[i]->type; + if (type == GLP_FR) + warning(csa, "range for free row '%s' ignored\n", + csa->P->row[i]->name); + else if (type == GLP_LO) + { rhs = csa->P->row[i]->lb; +#if 0 /* 26/V-2017 by cmatraki */ + glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, +#else + glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB, +#endif + rhs, rhs + fabs(rng)); + } + else if (type == GLP_UP) + { rhs = csa->P->row[i]->ub; +#if 0 /* 26/V-2017 by cmatraki */ + glp_set_row_bnds(csa->P, i, rhs == 0.0 ? GLP_FX : GLP_DB, +#else + glp_set_row_bnds(csa->P, i, rng == 0.0 ? GLP_FX : GLP_DB, +#endif + rhs - fabs(rng), rhs); + } + else if (type == GLP_FX) + { rhs = csa->P->row[i]->lb; + if (rng > 0.0) + glp_set_row_bnds(csa->P, i, GLP_DB, rhs, rhs + rng); + else if (rng < 0.0) + glp_set_row_bnds(csa->P, i, GLP_DB, rhs + rng, rhs); + } + else + xassert(type != type); + flag[i] = 1; + } + goto loop; +done: /* free working array */ + xfree(flag); + csa->work3 = NULL; + return; +} + +static void read_bounds(struct csa *csa) +{ /* read BOUNDS section */ + GLPCOL *col; + int j, v, mask, data; + double bnd, lb, ub; + char type[2+1], name[255+1], *flag; + /* allocate working array */ + csa->work3 = flag = xcalloc(1+csa->P->n, sizeof(char)); + memset(&flag[1], 0, csa->P->n); + /* no current BOUNDS vector exists */ + v = 0; +loop: if (indicator(csa, 0)) goto done; + /* field 1: bound type */ + read_field(csa); + if (strcmp(csa->field, "LO") == 0) + mask = 0x01, data = 1; + else if (strcmp(csa->field, "UP") == 0) + mask = 0x10, data = 1; + else if (strcmp(csa->field, "FX") == 0) + mask = 0x11, data = 1; + else if (strcmp(csa->field, "FR") == 0) + mask = 0x11, data = 0; + else if (strcmp(csa->field, "MI") == 0) + mask = 0x01, data = 0; + else if (strcmp(csa->field, "PL") == 0) + mask = 0x10, data = 0; + else if (strcmp(csa->field, "LI") == 0) + mask = 0x01, data = 1; + else if (strcmp(csa->field, "UI") == 0) + mask = 0x10, data = 1; + else if (strcmp(csa->field, "BV") == 0) + mask = 0x11, data = 0; + else if (csa->field[0] == '\0') + error(csa, "missing bound type in field 1\n"); + else + error(csa, "invalid bound type in field 1\n"); + strcpy(type, csa->field); + /* field 2: BOUNDS vector name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + { /* the same BOUNDS vector as in previous data record */ + if (v == 0) + { warning(csa, "missing BOUNDS vector name in field 2\n"); + goto blnk; + } + } + else if (v != 0 && strcmp(csa->field, name) == 0) + { /* the same BOUNDS vector as in previous data record */ + xassert(v != 0); + } + else +blnk: { /* new BOUNDS vector */ + if (v != 0) + error(csa, "multiple BOUNDS vectors not supported\n"); + v++; + strcpy(name, csa->field); + } + /* field 3: column name */ + read_field(csa), patch_name(csa, csa->field); + if (csa->field[0] == '\0') + error(csa, "missing column name in field 3\n"); + j = glp_find_col(csa->P, csa->field); + if (j == 0) + error(csa, "column '%s' not found\n", csa->field); + if ((flag[j] & mask) == 0x01) + error(csa, "duplicate lower bound for column '%s'\n", + csa->field); + if ((flag[j] & mask) == 0x10) + error(csa, "duplicate upper bound for column '%s'\n", + csa->field); + xassert((flag[j] & mask) == 0x00); + /* field 4: bound value */ + if (data) + { bnd = read_number(csa); + if (fabs(bnd) < csa->parm->tol_mps) bnd = 0.0; + } + else + read_field(csa), bnd = 0.0; + /* get current column bounds */ + col = csa->P->col[j]; + if (col->type == GLP_FR) + lb = -DBL_MAX, ub = +DBL_MAX; + else if (col->type == GLP_LO) + lb = col->lb, ub = +DBL_MAX; + else if (col->type == GLP_UP) + lb = -DBL_MAX, ub = col->ub; + else if (col->type == GLP_DB) + lb = col->lb, ub = col->ub; + else if (col->type == GLP_FX) + lb = ub = col->lb; + else + xassert(col != col); + /* change column bounds */ + if (strcmp(type, "LO") == 0) + lb = bnd; + else if (strcmp(type, "UP") == 0) + ub = bnd; + else if (strcmp(type, "FX") == 0) + lb = ub = bnd; + else if (strcmp(type, "FR") == 0) + lb = -DBL_MAX, ub = +DBL_MAX; + else if (strcmp(type, "MI") == 0) + lb = -DBL_MAX; + else if (strcmp(type, "PL") == 0) + ub = +DBL_MAX; + else if (strcmp(type, "LI") == 0) + { glp_set_col_kind(csa->P, j, GLP_IV); + lb = ceil(bnd); +#if 1 /* 16/VII-2013 */ + /* if column upper bound has not been explicitly specified, + take it as +inf */ + if (!(flag[j] & 0x10)) + ub = +DBL_MAX; +#endif + } + else if (strcmp(type, "UI") == 0) + { glp_set_col_kind(csa->P, j, GLP_IV); + ub = floor(bnd); + } + else if (strcmp(type, "BV") == 0) + { glp_set_col_kind(csa->P, j, GLP_IV); + lb = 0.0, ub = 1.0; + } + else + xassert(type != type); + /* set new column bounds */ + if (lb == -DBL_MAX && ub == +DBL_MAX) + glp_set_col_bnds(csa->P, j, GLP_FR, lb, ub); + else if (ub == +DBL_MAX) + glp_set_col_bnds(csa->P, j, GLP_LO, lb, ub); + else if (lb == -DBL_MAX) + glp_set_col_bnds(csa->P, j, GLP_UP, lb, ub); + else if (lb != ub) + glp_set_col_bnds(csa->P, j, GLP_DB, lb, ub); + else + glp_set_col_bnds(csa->P, j, GLP_FX, lb, ub); + flag[j] |= (char)mask; + /* fields 5 and 6 must be blank */ + skip_field(csa); + skip_field(csa); + goto loop; +done: /* free working array */ + xfree(flag); + csa->work3 = NULL; + return; +} + +int glp_read_mps(glp_prob *P, int fmt, const glp_mpscp *parm, + const char *fname) +{ /* read problem data in MPS format */ + glp_mpscp _parm; + struct csa _csa, *csa = &_csa; + int ret; + xprintf("Reading problem data from '%s'...\n", fname); + if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) + xerror("glp_read_mps: fmt = %d; invalid parameter\n", fmt); + if (parm == NULL) + glp_init_mpscp(&_parm), parm = &_parm; + /* check control parameters */ + check_parm("glp_read_mps", parm); + /* initialize common storage area */ + csa->P = P; + csa->deck = (fmt == GLP_MPS_DECK); + csa->parm = parm; + csa->fname = fname; + csa->fp = NULL; + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->recno = csa->recpos = 0; + csa->c = '\n'; + csa->fldno = 0; + csa->field[0] = '\0'; + csa->w80 = csa->wef = 0; + csa->obj_row = 0; + csa->work1 = csa->work2 = csa->work3 = NULL; + /* erase problem object */ + glp_erase_prob(P); + glp_create_index(P); + /* open input MPS file */ + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* read NAME indicator record */ + read_name(csa); + if (P->name != NULL) + xprintf("Problem: %s\n", P->name); + /* read ROWS section */ + if (!(indicator(csa, 0) && strcmp(csa->field, "ROWS") == 0)) + error(csa, "missing ROWS indicator record\n"); + read_rows(csa); + /* determine objective row */ + if (parm->obj_name == NULL || parm->obj_name[0] == '\0') + { /* use the first row of N type */ + int i; + for (i = 1; i <= P->m; i++) + { if (P->row[i]->type == GLP_FR) + { csa->obj_row = i; + break; + } + } + if (csa->obj_row == 0) + warning(csa, "unable to determine objective row\n"); + } + else + { /* use a row with specified name */ + int i; + for (i = 1; i <= P->m; i++) + { xassert(P->row[i]->name != NULL); + if (strcmp(parm->obj_name, P->row[i]->name) == 0) + { csa->obj_row = i; + break; + } + } + if (csa->obj_row == 0) + error(csa, "objective row '%s' not found\n", + parm->obj_name); + } + if (csa->obj_row != 0) + { glp_set_obj_name(P, P->row[csa->obj_row]->name); + xprintf("Objective: %s\n", P->obj); + } + /* read COLUMNS section */ + if (strcmp(csa->field, "COLUMNS") != 0) + error(csa, "missing COLUMNS indicator record\n"); + read_columns(csa); + /* set objective coefficients */ + if (csa->obj_row != 0) + { GLPAIJ *aij; + for (aij = P->row[csa->obj_row]->ptr; aij != NULL; aij = + aij->r_next) glp_set_obj_coef(P, aij->col->j, aij->val); + } + /* read optional RHS section */ + if (strcmp(csa->field, "RHS") == 0) + read_rhs(csa); + /* read optional RANGES section */ + if (strcmp(csa->field, "RANGES") == 0) + read_ranges(csa); + /* read optional BOUNDS section */ + if (strcmp(csa->field, "BOUNDS") == 0) + read_bounds(csa); + /* read ENDATA indicator record */ + if (strcmp(csa->field, "ENDATA") != 0) + error(csa, "invalid use of %s indicator record\n", + csa->field); + /* print some statistics */ + xprintf("%d row%s, %d column%s, %d non-zero%s\n", + P->m, P->m == 1 ? "" : "s", P->n, P->n == 1 ? "" : "s", + P->nnz, P->nnz == 1 ? "" : "s"); + if (glp_get_num_int(P) > 0) + { int ni = glp_get_num_int(P); + int nb = glp_get_num_bin(P); + if (ni == 1) + { if (nb == 0) + xprintf("One variable is integer\n"); + else + xprintf("One variable is binary\n"); + } + else + { xprintf("%d integer variables, ", ni); + if (nb == 0) + xprintf("none"); + else if (nb == 1) + xprintf("one"); + else if (nb == ni) + xprintf("all"); + else + xprintf("%d", nb); + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); + } + } + xprintf("%d records were read\n", csa->recno); +#if 1 /* 31/III-2016 */ + /* free (unbounded) row(s) in MPS file are intended to specify + * objective function(s), so all such rows can be removed */ +#if 1 /* 08/VIII-2013 */ + /* remove free rows */ + { int i, nrs, *num; + num = talloc(1+P->m, int); + nrs = 0; + for (i = 1; i <= P->m; i++) + { if (P->row[i]->type == GLP_FR) + num[++nrs] = i; + } + if (nrs > 0) + { glp_del_rows(P, nrs, num); + if (nrs == 1) + xprintf("One free row was removed\n"); + else + xprintf("%d free rows were removed\n", nrs); + } + tfree(num); + } +#endif +#else + /* if objective function row is free, remove it */ + if (csa->obj_row != 0 && P->row[csa->obj_row]->type == GLP_FR) + { int num[1+1]; + num[1] = csa->obj_row; + glp_del_rows(P, 1, num); + xprintf("Free objective row was removed\n"); + } +#endif + /* problem data has been successfully read */ + glp_delete_index(P); + glp_sort_matrix(P); + ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); + if (csa->work1 != NULL) xfree(csa->work1); + if (csa->work2 != NULL) xfree(csa->work2); + if (csa->work3 != NULL) xfree(csa->work3); + if (ret != 0) glp_erase_prob(P); + return ret; +} + +/*********************************************************************** +* NAME +* +* glp_write_mps - write problem data in MPS format +* +* SYNOPSIS +* +* int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_mps writes problem data in MPS format to a +* text file. +* +* The parameter fmt specifies the version of MPS format: +* +* GLP_MPS_DECK - fixed (ancient) MPS format; +* GLP_MPS_FILE - free (modern) MPS format. +* +* The parameter parm is a pointer to the structure glp_mpscp, which +* specifies control parameters used by the routine. If parm is NULL, +* the routine uses default settings. +* +* The character string fname specifies a name of the text file to be +* written. +* +* RETURNS +* +* If the operation was successful, the routine glp_read_mps returns +* zero. Otherwise, it prints an error message and returns non-zero. */ + +#define csa csa1 + +struct csa +{ /* common storage area */ + glp_prob *P; + /* pointer to problem object */ + int deck; + /* MPS format (0 - free, 1 - fixed) */ + const glp_mpscp *parm; + /* pointer to control parameters */ + char field[255+1]; + /* field buffer */ +}; + +static char *mps_name(struct csa *csa) +{ /* make problem name */ + char *f; + if (csa->P->name == NULL) + csa->field[0] = '\0'; + else if (csa->deck) + { strncpy(csa->field, csa->P->name, 8); + csa->field[8] = '\0'; + } + else + strcpy(csa->field, csa->P->name); + for (f = csa->field; *f != '\0'; f++) + if (*f == ' ') *f = '_'; + return csa->field; +} + +static char *row_name(struct csa *csa, int i) +{ /* make i-th row name */ + char *f; + xassert(0 <= i && i <= csa->P->m); + if (i == 0 || csa->P->row[i]->name == NULL || + csa->deck && strlen(csa->P->row[i]->name) > 8) + sprintf(csa->field, "R%07d", i); + else + { strcpy(csa->field, csa->P->row[i]->name); + for (f = csa->field; *f != '\0'; f++) + if (*f == ' ') *f = '_'; + } + return csa->field; +} + +static char *col_name(struct csa *csa, int j) +{ /* make j-th column name */ + char *f; + xassert(1 <= j && j <= csa->P->n); + if (csa->P->col[j]->name == NULL || + csa->deck && strlen(csa->P->col[j]->name) > 8) + sprintf(csa->field, "C%07d", j); + else + { strcpy(csa->field, csa->P->col[j]->name); + for (f = csa->field; *f != '\0'; f++) + if (*f == ' ') *f = '_'; + } + return csa->field; +} + +static char *mps_numb(struct csa *csa, double val) +{ /* format floating-point number */ + int dig; + char *exp; + for (dig = 12; dig >= 6; dig--) + { if (val != 0.0 && fabs(val) < 0.002) + sprintf(csa->field, "%.*E", dig-1, val); + else + sprintf(csa->field, "%.*G", dig, val); + exp = strchr(csa->field, 'E'); + if (exp != NULL) + sprintf(exp+1, "%d", atoi(exp+1)); + if (strlen(csa->field) <= 12) break; + } + xassert(strlen(csa->field) <= 12); + return csa->field; +} + +int glp_write_mps(glp_prob *P, int fmt, const glp_mpscp *parm, + const char *fname) +{ /* write problem data in MPS format */ + glp_mpscp _parm; + struct csa _csa, *csa = &_csa; + glp_file *fp; + int out_obj, one_col = 0, empty = 0; + int i, j, recno, marker, count, gap, ret; + xprintf("Writing problem data to '%s'...\n", fname); + if (!(fmt == GLP_MPS_DECK || fmt == GLP_MPS_FILE)) + xerror("glp_write_mps: fmt = %d; invalid parameter\n", fmt); + if (parm == NULL) + glp_init_mpscp(&_parm), parm = &_parm; + /* check control parameters */ + check_parm("glp_write_mps", parm); + /* initialize common storage area */ + csa->P = P; + csa->deck = (fmt == GLP_MPS_DECK); + csa->parm = parm; + /* create output MPS file */ + fp = glp_open(fname, "w"), recno = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* write comment records */ + xfprintf(fp, "* %-*s%s\n", P->name == NULL ? 1 : 12, "Problem:", + P->name == NULL ? "" : P->name), recno++; + xfprintf(fp, "* %-12s%s\n", "Class:", glp_get_num_int(P) == 0 ? + "LP" : "MIP"), recno++; + xfprintf(fp, "* %-12s%d\n", "Rows:", P->m), recno++; + if (glp_get_num_int(P) == 0) + xfprintf(fp, "* %-12s%d\n", "Columns:", P->n), recno++; + else + xfprintf(fp, "* %-12s%d (%d integer, %d binary)\n", + "Columns:", P->n, glp_get_num_int(P), glp_get_num_bin(P)), + recno++; + xfprintf(fp, "* %-12s%d\n", "Non-zeros:", P->nnz), recno++; + xfprintf(fp, "* %-12s%s\n", "Format:", csa->deck ? "Fixed MPS" : + "Free MPS"), recno++; + xfprintf(fp, "*\n", recno++); + /* write NAME indicator record */ + xfprintf(fp, "NAME%*s%s\n", + P->name == NULL ? 0 : csa->deck ? 10 : 1, "", mps_name(csa)), + recno++; +#if 1 + /* determine whether to write the objective row */ + out_obj = 1; + for (i = 1; i <= P->m; i++) + { if (P->row[i]->type == GLP_FR) + { out_obj = 0; + break; + } + } +#endif + /* write ROWS section */ + xfprintf(fp, "ROWS\n"), recno++; + for (i = (out_obj ? 0 : 1); i <= P->m; i++) + { int type; + type = (i == 0 ? GLP_FR : P->row[i]->type); + if (type == GLP_FR) + type = 'N'; + else if (type == GLP_LO) + type = 'G'; + else if (type == GLP_UP) + type = 'L'; + else if (type == GLP_DB || type == GLP_FX) + type = 'E'; + else + xassert(type != type); + xfprintf(fp, " %c%*s%s\n", type, csa->deck ? 2 : 1, "", + row_name(csa, i)), recno++; + } + /* write COLUMNS section */ + xfprintf(fp, "COLUMNS\n"), recno++; + marker = 0; + for (j = 1; j <= P->n; j++) + { GLPAIJ cj, *aij; + int kind; + kind = P->col[j]->kind; + if (kind == GLP_CV) + { if (marker % 2 == 1) + { /* close current integer block */ + marker++; + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", + csa->deck ? 17 : 1, ""), recno++; + } + } + else if (kind == GLP_IV) + { if (marker % 2 == 0) + { /* open new integer block */ + marker++; + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTORG'\n", + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", + csa->deck ? 17 : 1, ""), recno++; + } + } + else + xassert(kind != kind); + if (out_obj && P->col[j]->coef != 0.0) + { /* make fake objective coefficient */ + aij = &cj; + aij->row = NULL; + aij->val = P->col[j]->coef; + aij->c_next = P->col[j]->ptr; + } + else + aij = P->col[j]->ptr; +#if 1 /* FIXME */ + if (aij == NULL) + { /* empty column */ + empty++; + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", + csa->deck ? 8 : 1, col_name(csa, j)); + /* we need a row */ + xassert(P->m > 0); + xfprintf(fp, "%*s%-*s", + csa->deck ? 2 : 1, "", csa->deck ? 8 : 1, + row_name(csa, 1)); + xfprintf(fp, "%*s0%*s$ empty column\n", + csa->deck ? 13 : 1, "", csa->deck ? 3 : 1, ""), recno++; + } +#endif + count = 0; + for (aij = aij; aij != NULL; aij = aij->c_next) + { if (one_col || count % 2 == 0) + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", + csa->deck ? 8 : 1, col_name(csa, j)); + gap = (one_col || count % 2 == 0 ? 2 : 3); + xfprintf(fp, "%*s%-*s", + csa->deck ? gap : 1, "", csa->deck ? 8 : 1, + row_name(csa, aij->row == NULL ? 0 : aij->row->i)); + xfprintf(fp, "%*s%*s", + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, + mps_numb(csa, aij->val)), count++; + if (one_col || count % 2 == 0) + xfprintf(fp, "\n"), recno++; + } + if (!(one_col || count % 2 == 0)) + xfprintf(fp, "\n"), recno++; + } + if (marker % 2 == 1) + { /* close last integer block */ + marker++; + xfprintf(fp, "%*sM%07d%*s'MARKER'%*s'INTEND'\n", + csa->deck ? 4 : 1, "", marker, csa->deck ? 2 : 1, "", + csa->deck ? 17 : 1, ""), recno++; + } +#if 1 + if (empty > 0) + xprintf("Warning: problem has %d empty column(s)\n", empty); +#endif + /* write RHS section */ + xfprintf(fp, "RHS\n"), recno++; + count = 0; + for (i = (out_obj ? 0 : 1); i <= P->m; i++) + { int type; + double rhs; + if (i == 0) + rhs = P->c0; + else + { type = P->row[i]->type; + if (type == GLP_FR) + rhs = 0.0; + else if (type == GLP_LO) + rhs = P->row[i]->lb; + else if (type == GLP_UP) + rhs = P->row[i]->ub; + else if (type == GLP_DB || type == GLP_FX) + rhs = P->row[i]->lb; + else + xassert(type != type); + } + if (rhs != 0.0) + { if (one_col || count % 2 == 0) + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", + csa->deck ? 8 : 1, "RHS1"); + gap = (one_col || count % 2 == 0 ? 2 : 3); + xfprintf(fp, "%*s%-*s", + csa->deck ? gap : 1, "", csa->deck ? 8 : 1, + row_name(csa, i)); + xfprintf(fp, "%*s%*s", + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, + mps_numb(csa, rhs)), count++; + if (one_col || count % 2 == 0) + xfprintf(fp, "\n"), recno++; + } + } + if (!(one_col || count % 2 == 0)) + xfprintf(fp, "\n"), recno++; + /* write RANGES section */ + for (i = P->m; i >= 1; i--) + if (P->row[i]->type == GLP_DB) break; + if (i == 0) goto bnds; + xfprintf(fp, "RANGES\n"), recno++; + count = 0; + for (i = 1; i <= P->m; i++) + { if (P->row[i]->type == GLP_DB) + { if (one_col || count % 2 == 0) + xfprintf(fp, "%*s%-*s", csa->deck ? 4 : 1, "", + csa->deck ? 8 : 1, "RNG1"); + gap = (one_col || count % 2 == 0 ? 2 : 3); + xfprintf(fp, "%*s%-*s", + csa->deck ? gap : 1, "", csa->deck ? 8 : 1, + row_name(csa, i)); + xfprintf(fp, "%*s%*s", + csa->deck ? 2 : 1, "", csa->deck ? 12 : 1, + mps_numb(csa, P->row[i]->ub - P->row[i]->lb)), count++; + if (one_col || count % 2 == 0) + xfprintf(fp, "\n"), recno++; + } + } + if (!(one_col || count % 2 == 0)) + xfprintf(fp, "\n"), recno++; +bnds: /* write BOUNDS section */ + for (j = P->n; j >= 1; j--) + if (!(P->col[j]->kind == GLP_CV && + P->col[j]->type == GLP_LO && P->col[j]->lb == 0.0)) + break; + if (j == 0) goto endt; + xfprintf(fp, "BOUNDS\n"), recno++; + for (j = 1; j <= P->n; j++) + { int type, data[2]; + double bnd[2]; + char *spec[2]; + spec[0] = spec[1] = NULL; + type = P->col[j]->type; + if (type == GLP_FR) + spec[0] = "FR", data[0] = 0; + else if (type == GLP_LO) + { if (P->col[j]->lb != 0.0) + spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; + if (P->col[j]->kind == GLP_IV) + spec[1] = "PL", data[1] = 0; + } + else if (type == GLP_UP) + { spec[0] = "MI", data[0] = 0; + spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; + } + else if (type == GLP_DB) + { if (P->col[j]->lb != 0.0) + spec[0] = "LO", data[0] = 1, bnd[0] = P->col[j]->lb; + spec[1] = "UP", data[1] = 1, bnd[1] = P->col[j]->ub; + } + else if (type == GLP_FX) + spec[0] = "FX", data[0] = 1, bnd[0] = P->col[j]->lb; + else + xassert(type != type); + for (i = 0; i <= 1; i++) + { if (spec[i] != NULL) + { xfprintf(fp, " %s %-*s%*s%-*s", spec[i], + csa->deck ? 8 : 1, "BND1", csa->deck ? 2 : 1, "", + csa->deck ? 8 : 1, col_name(csa, j)); + if (data[i]) + xfprintf(fp, "%*s%*s", csa->deck ? 2 : 1, "", + csa->deck ? 12 : 1, mps_numb(csa, bnd[i])); + xfprintf(fp, "\n"), recno++; + } + } + } +endt: /* write ENDATA indicator record */ + xfprintf(fp, "ENDATA\n"), recno++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* problem data has been successfully written */ + xprintf("%d records were written\n", recno); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/netgen.c b/glpk-5.0/src/api/netgen.c new file mode 100644 index 0000000..ec556ad --- /dev/null +++ b/glpk-5.0/src/api/netgen.c @@ -0,0 +1,20 @@ +/* netgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_netgen(glp_graph *G_, int v_rhs_, int a_cap_, int a_cost_, + const int parm[1+15]) +{ static const char func[] = "glp_netgen"; + xassert(G_ == G_); + xassert(v_rhs_ == v_rhs_); + xassert(a_cap_ == a_cap_); + xassert(a_cost_ == a_cost_); + xassert(parm == parm); + xerror("%s: sorry, this routine is temporarily disabled due to li" + "censing problems\n", func); + abort(); + return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/npp.c b/glpk-5.0/src/api/npp.c new file mode 100644 index 0000000..ec7be18 --- /dev/null +++ b/glpk-5.0/src/api/npp.c @@ -0,0 +1,141 @@ +/* npp.c (LP/MIP preprocessing) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2017 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "npp.h" + +glp_prep *glp_npp_alloc_wksp(void) +{ /* allocate the preprocessor workspace */ + glp_prep *prep; + prep = npp_create_wksp(); + return prep; +} + +void glp_npp_load_prob(glp_prep *prep, glp_prob *P, int sol, int names) +{ /* load original problem instance */ + if (prep->sol != 0) + xerror("glp_npp_load_prob: invalid call sequence (original ins" + "tance already loaded)\n"); + if (!(sol == GLP_SOL || sol == GLP_IPT || sol == GLP_MIP)) + xerror("glp_npp_load_prob: sol = %d; invalid parameter\n", + sol); + if (!(names == GLP_ON || names == GLP_OFF)) + xerror("glp_npp_load_prob: names = %d; invalid parameter\n", + names); + npp_load_prob(prep, P, names, sol, GLP_OFF); + return; +} + +int glp_npp_preprocess1(glp_prep *prep, int hard) +{ /* perform basic LP/MIP preprocessing */ + if (prep->sol == 0) + xerror("glp_npp_preprocess1: invalid call sequence (original i" + "nstance not loaded yet)\n"); + if (prep->pool == NULL) + xerror("glp_npp_preprocess1: invalid call sequence (preprocess" + "ing already finished)\n"); + if (!(hard == GLP_ON || hard == GLP_OFF)) + xerror("glp_npp_preprocess1: hard = %d; invalid parameter\n", + hard); + return npp_process_prob(prep, hard); +} + +void glp_npp_build_prob(glp_prep *prep, glp_prob *Q) +{ /* build resultant problem instance */ + if (prep->sol == 0) + xerror("glp_npp_build_prob: invalid call sequence (original in" + "stance not loaded yet)\n"); + if (prep->pool == NULL) + xerror("glp_npp_build_prob: invalid call sequence (resultant i" + "nstance already built)\n"); + npp_build_prob(prep, Q); + return; +} + +void glp_npp_postprocess(glp_prep *prep, glp_prob *Q) +{ /* postprocess solution to resultant problem */ + if (prep->pool != NULL) + xerror("glp_npp_postprocess: invalid call sequence (resultant " + "instance not built yet)\n"); + if (!(prep->m == Q->m && prep->n == Q->n && prep->nnz == Q->nnz)) + xerror("glp_npp_postprocess: resultant instance mismatch\n"); + switch (prep->sol) + { case GLP_SOL: + if (glp_get_status(Q) != GLP_OPT) + xerror("glp_npp_postprocess: unable to recover non-optim" + "al basic solution\n"); + break; + case GLP_IPT: + if (glp_ipt_status(Q) != GLP_OPT) + xerror("glp_npp_postprocess: unable to recover non-optim" + "al interior-point solution\n"); + break; + case GLP_MIP: + if (!(glp_mip_status(Q) == GLP_OPT || glp_mip_status(Q) == + GLP_FEAS)) + xerror("glp_npp_postprocess: unable to recover integer n" + "on-feasible solution\n"); + break; + default: + xassert(prep != prep); + } + npp_postprocess(prep, Q); + return; +} + +void glp_npp_obtain_sol(glp_prep *prep, glp_prob *P) +{ /* obtain solution to original problem */ + if (prep->pool != NULL) + xerror("glp_npp_obtain_sol: invalid call sequence (resultant i" + "nstance not built yet)\n"); + switch (prep->sol) + { case GLP_SOL: + if (prep->p_stat == 0 || prep->d_stat == 0) + xerror("glp_npp_obtain_sol: invalid call sequence (basic" + " solution not provided yet)\n"); + break; + case GLP_IPT: + if (prep->t_stat == 0) + xerror("glp_npp_obtain_sol: invalid call sequence (inter" + "ior-point solution not provided yet)\n"); + break; + case GLP_MIP: + if (prep->i_stat == 0) + xerror("glp_npp_obtain_sol: invalid call sequence (MIP s" + "olution not provided yet)\n"); + break; + default: + xassert(prep != prep); + } + if (!(prep->orig_dir == P->dir && prep->orig_m == P->m && + prep->orig_n == P->n && prep->orig_nnz == P->nnz)) + xerror("glp_npp_obtain_sol: original instance mismatch\n"); + npp_unload_sol(prep, P); + return; +} + +void glp_npp_free_wksp(glp_prep *prep) +{ /* free the preprocessor workspace */ + npp_delete_wksp(prep); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/pript.c b/glpk-5.0/src/api/pript.c new file mode 100644 index 0000000..968236b --- /dev/null +++ b/glpk-5.0/src/api/pript.c @@ -0,0 +1,184 @@ +/* pript.c (write interior-point solution in printable format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_ipt(glp_prob *P, const char *fname) +{ /* write interior-point solution in printable format */ + glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, t, ae_ind, re_ind, ret; + double ae_max, re_max; + xprintf("Writing interior-point solution to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "%-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name); + xfprintf(fp, "%-12s%d\n", "Rows:", P->m); + xfprintf(fp, "%-12s%d\n", "Columns:", P->n); + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); + t = glp_ipt_status(P); + xfprintf(fp, "%-12s%s\n", "Status:", + t == GLP_OPT ? "OPTIMAL" : + t == GLP_UNDEF ? "UNDEFINED" : + t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : + t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : "???"); + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->ipt_obj, + P->dir == GLP_MIN ? "MINimum" : + P->dir == GLP_MAX ? "MAXimum" : "???"); + xfprintf(fp, "\n"); + xfprintf(fp, " No. Row name Activity Lower bound " + " Upper bound Marginal\n"); + xfprintf(fp, "------ ------------ ------------- ------------- " + "------------- -------------\n"); + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + xfprintf(fp, "%6d ", i); + if (row->name == NULL || strlen(row->name) <= 12) + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); + else + xfprintf(fp, "%s\n%20s", row->name, ""); + xfprintf(fp, "%3s", ""); + xfprintf(fp, "%13.6g ", + fabs(row->pval) <= 1e-9 ? 0.0 : row->pval); + if (row->type == GLP_LO || row->type == GLP_DB || + row->type == GLP_FX) + xfprintf(fp, "%13.6g ", row->lb); + else + xfprintf(fp, "%13s ", ""); + if (row->type == GLP_UP || row->type == GLP_DB) + xfprintf(fp, "%13.6g ", row->ub); + else + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); + if (fabs(row->dval) <= 1e-9) + xfprintf(fp, "%13s", "< eps"); + else + xfprintf(fp, "%13.6g ", row->dval); + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, " No. Column name Activity Lower bound " + " Upper bound Marginal\n"); + xfprintf(fp, "------ ------------ ------------- ------------- " + "------------- -------------\n"); + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + xfprintf(fp, "%6d ", j); + if (col->name == NULL || strlen(col->name) <= 12) + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); + else + xfprintf(fp, "%s\n%20s", col->name, ""); + xfprintf(fp, "%3s", ""); + xfprintf(fp, "%13.6g ", + fabs(col->pval) <= 1e-9 ? 0.0 : col->pval); + if (col->type == GLP_LO || col->type == GLP_DB || + col->type == GLP_FX) + xfprintf(fp, "%13.6g ", col->lb); + else + xfprintf(fp, "%13s ", ""); + if (col->type == GLP_UP || col->type == GLP_DB) + xfprintf(fp, "%13.6g ", col->ub); + else + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); + if (fabs(col->dval) <= 1e-9) + xfprintf(fp, "%13s", "< eps"); + else + xfprintf(fp, "%13.6g ", col->dval); + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_IPT, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", + ae_max, ae_ind); + xfprintf(fp, " max.rel.err = %.2e on row %d\n", + re_max, re_ind); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_IPT, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", + ae_max, ae_ind <= P->m ? "row" : "column", + ae_ind <= P->m ? ae_ind : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on %s %d\n", + re_max, re_ind <= P->m ? "row" : "column", + re_ind <= P->m ? re_ind : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" + "E"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_IPT, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", + ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on column %d\n", + re_max, re_ind == 0 ? 0 : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_IPT, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", + ae_max, ae_ind <= P->m ? "row" : "column", + ae_ind <= P->m ? ae_ind : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on %s %d\n", + re_max, re_ind <= P->m ? "row" : "column", + re_ind <= P->m ? re_ind : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") + ; + xfprintf(fp, "\n"); + xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prmip.c b/glpk-5.0/src/api/prmip.c new file mode 100644 index 0000000..81d52c8 --- /dev/null +++ b/glpk-5.0/src/api/prmip.c @@ -0,0 +1,153 @@ +/* prmip.c (write MIP solution in printable format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_mip(glp_prob *P, const char *fname) +{ /* write MIP solution in printable format */ + glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, t, ae_ind, re_ind, ret; + double ae_max, re_max; + xprintf("Writing MIP solution to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "%-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name); + xfprintf(fp, "%-12s%d\n", "Rows:", P->m); + xfprintf(fp, "%-12s%d (%d integer, %d binary)\n", "Columns:", + P->n, glp_get_num_int(P), glp_get_num_bin(P)); + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); + t = glp_mip_status(P); + xfprintf(fp, "%-12s%s\n", "Status:", + t == GLP_OPT ? "INTEGER OPTIMAL" : + t == GLP_FEAS ? "INTEGER NON-OPTIMAL" : + t == GLP_NOFEAS ? "INTEGER EMPTY" : + t == GLP_UNDEF ? "INTEGER UNDEFINED" : "???"); + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->mip_obj, + P->dir == GLP_MIN ? "MINimum" : + P->dir == GLP_MAX ? "MAXimum" : "???"); + xfprintf(fp, "\n"); + xfprintf(fp, " No. Row name Activity Lower bound " + " Upper bound\n"); + xfprintf(fp, "------ ------------ ------------- ------------- " + "-------------\n"); + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + xfprintf(fp, "%6d ", i); + if (row->name == NULL || strlen(row->name) <= 12) + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); + else + xfprintf(fp, "%s\n%20s", row->name, ""); + xfprintf(fp, "%3s", ""); + xfprintf(fp, "%13.6g ", + fabs(row->mipx) <= 1e-9 ? 0.0 : row->mipx); + if (row->type == GLP_LO || row->type == GLP_DB || + row->type == GLP_FX) + xfprintf(fp, "%13.6g ", row->lb); + else + xfprintf(fp, "%13s ", ""); + if (row->type == GLP_UP || row->type == GLP_DB) + xfprintf(fp, "%13.6g ", row->ub); + else + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, " No. Column name Activity Lower bound " + " Upper bound\n"); + xfprintf(fp, "------ ------------ ------------- ------------- " + "-------------\n"); + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + xfprintf(fp, "%6d ", j); + if (col->name == NULL || strlen(col->name) <= 12) + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); + else + xfprintf(fp, "%s\n%20s", col->name, ""); + xfprintf(fp, "%s ", + col->kind == GLP_CV ? " " : + col->kind == GLP_IV ? "*" : "?"); + xfprintf(fp, "%13.6g ", + fabs(col->mipx) <= 1e-9 ? 0.0 : col->mipx); + if (col->type == GLP_LO || col->type == GLP_DB || + col->type == GLP_FX) + xfprintf(fp, "%13.6g ", col->lb); + else + xfprintf(fp, "%13s ", ""); + if (col->type == GLP_UP || col->type == GLP_DB) + xfprintf(fp, "%13.6g ", col->ub); + else + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, "Integer feasibility conditions:\n"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_MIP, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", + ae_max, ae_ind); + xfprintf(fp, " max.rel.err = %.2e on row %d\n", + re_max, re_ind); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "SOLUTION IS WRONG"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_MIP, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", + ae_max, ae_ind <= P->m ? "row" : "column", + ae_ind <= P->m ? ae_ind : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on %s %d\n", + re_max, re_ind <= P->m ? "row" : "column", + re_ind <= P->m ? re_ind : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "SOLUTION IS INFEASIBLE"); + xfprintf(fp, "\n"); + xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob.h b/glpk-5.0/src/api/prob.h new file mode 100644 index 0000000..9a20fd9 --- /dev/null +++ b/glpk-5.0/src/api/prob.h @@ -0,0 +1,284 @@ +/* prob.h (LP/MIP problem object) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2013 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#ifndef PROB_H +#define PROB_H + +#include "avl.h" +#include "bfd.h" +#include "dmp.h" +#if 1 /* 28/III-2016 */ +#define GLP_UNDOC 1 +#endif +#include "glpk.h" + +typedef struct GLPROW GLPROW; +typedef struct GLPCOL GLPCOL; +typedef struct GLPAIJ GLPAIJ; + +#if 0 /* 04/IV-2016 */ +#define GLP_PROB_MAGIC 0xD7D9D6C2 +#endif + +struct glp_prob +{ /* LP/MIP problem object */ +#if 0 /* 04/IV-2016 */ + unsigned magic; + /* magic value used for debugging */ +#endif + DMP *pool; + /* memory pool to store problem object components */ + glp_tree *tree; + /* pointer to the search tree; set by the MIP solver when this + object is used in the tree as a core MIP object */ +#if 0 /* 08/III-2014 */ + void *parms; + /* reserved for backward compatibility */ +#endif + /*--------------------------------------------------------------*/ + /* LP/MIP data */ + char *name; + /* problem name (1 to 255 chars); NULL means no name is assigned + to the problem */ + char *obj; + /* objective function name (1 to 255 chars); NULL means no name + is assigned to the objective function */ + int dir; + /* optimization direction flag (objective "sense"): + GLP_MIN - minimization + GLP_MAX - maximization */ + double c0; + /* constant term of the objective function ("shift") */ + int m_max; + /* length of the array of rows (enlarged automatically) */ + int n_max; + /* length of the array of columns (enlarged automatically) */ + int m; + /* number of rows, 0 <= m <= m_max */ + int n; + /* number of columns, 0 <= n <= n_max */ + int nnz; + /* number of non-zero constraint coefficients, nnz >= 0 */ + GLPROW **row; /* GLPROW *row[1+m_max]; */ + /* row[i], 1 <= i <= m, is a pointer to i-th row */ + GLPCOL **col; /* GLPCOL *col[1+n_max]; */ + /* col[j], 1 <= j <= n, is a pointer to j-th column */ + AVL *r_tree; + /* row index to find rows by their names; NULL means this index + does not exist */ + AVL *c_tree; + /* column index to find columns by their names; NULL means this + index does not exist */ + /*--------------------------------------------------------------*/ + /* basis factorization (LP) */ + int valid; + /* the factorization is valid only if this flag is set */ + int *head; /* int head[1+m_max]; */ + /* basis header (valid only if the factorization is valid); + head[i] = k is the ordinal number of auxiliary (1 <= k <= m) + or structural (m+1 <= k <= m+n) variable which corresponds to + i-th basic variable xB[i], 1 <= i <= m */ +#if 0 /* 08/III-2014 */ + glp_bfcp *bfcp; + /* basis factorization control parameters; may be NULL */ +#endif + BFD *bfd; /* BFD bfd[1:m,1:m]; */ + /* basis factorization driver; may be NULL */ + /*--------------------------------------------------------------*/ + /* basic solution (LP) */ + int pbs_stat; + /* primal basic solution status: + GLP_UNDEF - primal solution is undefined + GLP_FEAS - primal solution is feasible + GLP_INFEAS - primal solution is infeasible + GLP_NOFEAS - no primal feasible solution exists */ + int dbs_stat; + /* dual basic solution status: + GLP_UNDEF - dual solution is undefined + GLP_FEAS - dual solution is feasible + GLP_INFEAS - dual solution is infeasible + GLP_NOFEAS - no dual feasible solution exists */ + double obj_val; + /* objective function value */ + int it_cnt; + /* simplex method iteration count; increases by one on performing + one simplex iteration */ + int some; + /* ordinal number of some auxiliary or structural variable having + certain property, 0 <= some <= m+n */ + /*--------------------------------------------------------------*/ + /* interior-point solution (LP) */ + int ipt_stat; + /* interior-point solution status: + GLP_UNDEF - interior solution is undefined + GLP_OPT - interior solution is optimal + GLP_INFEAS - interior solution is infeasible + GLP_NOFEAS - no feasible solution exists */ + double ipt_obj; + /* objective function value */ + /*--------------------------------------------------------------*/ + /* integer solution (MIP) */ + int mip_stat; + /* integer solution status: + GLP_UNDEF - integer solution is undefined + GLP_OPT - integer solution is optimal + GLP_FEAS - integer solution is feasible + GLP_NOFEAS - no integer solution exists */ + double mip_obj; + /* objective function value */ +}; + +struct GLPROW +{ /* LP/MIP row (auxiliary variable) */ + int i; + /* ordinal number (1 to m) assigned to this row */ + char *name; + /* row name (1 to 255 chars); NULL means no name is assigned to + this row */ + AVLNODE *node; + /* pointer to corresponding node in the row index; NULL means + that either the row index does not exist or this row has no + name assigned */ +#if 1 /* 20/IX-2008 */ + int level; + unsigned char origin; + unsigned char klass; +#endif + int type; + /* type of the auxiliary variable: + GLP_FR - free variable + GLP_LO - variable with lower bound + GLP_UP - variable with upper bound + GLP_DB - double-bounded variable + GLP_FX - fixed variable */ + double lb; /* non-scaled */ + /* lower bound; if the row has no lower bound, lb is zero */ + double ub; /* non-scaled */ + /* upper bound; if the row has no upper bound, ub is zero */ + /* if the row type is GLP_FX, ub is equal to lb */ + GLPAIJ *ptr; /* non-scaled */ + /* pointer to doubly linked list of constraint coefficients which + are placed in this row */ + double rii; + /* diagonal element r[i,i] of scaling matrix R for this row; + if the scaling is not used, r[i,i] is 1 */ + int stat; + /* status of the auxiliary variable: + GLP_BS - basic variable + GLP_NL - non-basic variable on lower bound + GLP_NU - non-basic variable on upper bound + GLP_NF - non-basic free variable + GLP_NS - non-basic fixed variable */ + int bind; + /* if the auxiliary variable is basic, head[bind] refers to this + row, otherwise, bind is 0; this attribute is valid only if the + basis factorization is valid */ + double prim; /* non-scaled */ + /* primal value of the auxiliary variable in basic solution */ + double dual; /* non-scaled */ + /* dual value of the auxiliary variable in basic solution */ + double pval; /* non-scaled */ + /* primal value of the auxiliary variable in interior solution */ + double dval; /* non-scaled */ + /* dual value of the auxiliary variable in interior solution */ + double mipx; /* non-scaled */ + /* primal value of the auxiliary variable in integer solution */ +}; + +struct GLPCOL +{ /* LP/MIP column (structural variable) */ + int j; + /* ordinal number (1 to n) assigned to this column */ + char *name; + /* column name (1 to 255 chars); NULL means no name is assigned + to this column */ + AVLNODE *node; + /* pointer to corresponding node in the column index; NULL means + that either the column index does not exist or the column has + no name assigned */ + int kind; + /* kind of the structural variable: + GLP_CV - continuous variable + GLP_IV - integer or binary variable */ + int type; + /* type of the structural variable: + GLP_FR - free variable + GLP_LO - variable with lower bound + GLP_UP - variable with upper bound + GLP_DB - double-bounded variable + GLP_FX - fixed variable */ + double lb; /* non-scaled */ + /* lower bound; if the column has no lower bound, lb is zero */ + double ub; /* non-scaled */ + /* upper bound; if the column has no upper bound, ub is zero */ + /* if the column type is GLP_FX, ub is equal to lb */ + double coef; /* non-scaled */ + /* objective coefficient at the structural variable */ + GLPAIJ *ptr; /* non-scaled */ + /* pointer to doubly linked list of constraint coefficients which + are placed in this column */ + double sjj; + /* diagonal element s[j,j] of scaling matrix S for this column; + if the scaling is not used, s[j,j] is 1 */ + int stat; + /* status of the structural variable: + GLP_BS - basic variable + GLP_NL - non-basic variable on lower bound + GLP_NU - non-basic variable on upper bound + GLP_NF - non-basic free variable + GLP_NS - non-basic fixed variable */ + int bind; + /* if the structural variable is basic, head[bind] refers to + this column; otherwise, bind is 0; this attribute is valid only + if the basis factorization is valid */ + double prim; /* non-scaled */ + /* primal value of the structural variable in basic solution */ + double dual; /* non-scaled */ + /* dual value of the structural variable in basic solution */ + double pval; /* non-scaled */ + /* primal value of the structural variable in interior solution */ + double dval; /* non-scaled */ + /* dual value of the structural variable in interior solution */ + double mipx; /* non-scaled */ + /* primal value of the structural variable in integer solution */ +}; + +struct GLPAIJ +{ /* constraint coefficient a[i,j] */ + GLPROW *row; + /* pointer to row, where this coefficient is placed */ + GLPCOL *col; + /* pointer to column, where this coefficient is placed */ + double val; + /* numeric (non-zero) value of this coefficient */ + GLPAIJ *r_prev; + /* pointer to previous coefficient in the same row */ + GLPAIJ *r_next; + /* pointer to next coefficient in the same row */ + GLPAIJ *c_prev; + /* pointer to previous coefficient in the same column */ + GLPAIJ *c_next; + /* pointer to next coefficient in the same column */ +}; + +#endif + +/* eof */ diff --git a/glpk-5.0/src/api/prob1.c b/glpk-5.0/src/api/prob1.c new file mode 100644 index 0000000..5fe1ab7 --- /dev/null +++ b/glpk-5.0/src/api/prob1.c @@ -0,0 +1,1586 @@ +/* prob1.c (problem creating and modifying routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2018 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "ios.h" + +/* CAUTION: DO NOT CHANGE THE LIMITS BELOW */ + +#define M_MAX 100000000 /* = 100*10^6 */ +/* maximal number of rows in the problem object */ + +#define N_MAX 100000000 /* = 100*10^6 */ +/* maximal number of columns in the problem object */ + +#define NNZ_MAX 500000000 /* = 500*10^6 */ +/* maximal number of constraint coefficients in the problem object */ + +/*********************************************************************** +* NAME +* +* glp_create_prob - create problem object +* +* SYNOPSIS +* +* glp_prob *glp_create_prob(void); +* +* DESCRIPTION +* +* The routine glp_create_prob creates a new problem object, which is +* initially "empty", i.e. has no rows and columns. +* +* RETURNS +* +* The routine returns a pointer to the object created, which should be +* used in any subsequent operations on this object. */ + +static void create_prob(glp_prob *lp) +#if 0 /* 04/IV-2016 */ +{ lp->magic = GLP_PROB_MAGIC; +#else +{ +#endif + lp->pool = dmp_create_pool(); +#if 0 /* 08/III-2014 */ +#if 0 /* 17/XI-2009 */ + lp->cps = xmalloc(sizeof(struct LPXCPS)); + lpx_reset_parms(lp); +#else + lp->parms = NULL; +#endif +#endif + lp->tree = NULL; +#if 0 + lp->lwa = 0; + lp->cwa = NULL; +#endif + /* LP/MIP data */ + lp->name = NULL; + lp->obj = NULL; + lp->dir = GLP_MIN; + lp->c0 = 0.0; + lp->m_max = 100; + lp->n_max = 200; + lp->m = lp->n = 0; + lp->nnz = 0; + lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); + lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); + lp->r_tree = lp->c_tree = NULL; + /* basis factorization */ + lp->valid = 0; + lp->head = xcalloc(1+lp->m_max, sizeof(int)); +#if 0 /* 08/III-2014 */ + lp->bfcp = NULL; +#endif + lp->bfd = NULL; + /* basic solution (LP) */ + lp->pbs_stat = lp->dbs_stat = GLP_UNDEF; + lp->obj_val = 0.0; + lp->it_cnt = 0; + lp->some = 0; + /* interior-point solution (LP) */ + lp->ipt_stat = GLP_UNDEF; + lp->ipt_obj = 0.0; + /* integer solution (MIP) */ + lp->mip_stat = GLP_UNDEF; + lp->mip_obj = 0.0; + return; +} + +glp_prob *glp_create_prob(void) +{ glp_prob *lp; + lp = xmalloc(sizeof(glp_prob)); + create_prob(lp); + return lp; +} + +/*********************************************************************** +* NAME +* +* glp_set_prob_name - assign (change) problem name +* +* SYNOPSIS +* +* void glp_set_prob_name(glp_prob *lp, const char *name); +* +* DESCRIPTION +* +* The routine glp_set_prob_name assigns a given symbolic name (1 up to +* 255 characters) to the specified problem object. +* +* If the parameter name is NULL or empty string, the routine erases an +* existing symbolic name of the problem object. */ + +void glp_set_prob_name(glp_prob *lp, const char *name) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_prob_name: operation not allowed\n"); + if (lp->name != NULL) + { dmp_free_atom(lp->pool, lp->name, strlen(lp->name)+1); + lp->name = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int k; + for (k = 0; name[k] != '\0'; k++) + { if (k == 256) + xerror("glp_set_prob_name: problem name too long\n"); + if (iscntrl((unsigned char)name[k])) + xerror("glp_set_prob_name: problem name contains invalid" + " character(s)\n"); + } + lp->name = dmp_get_atom(lp->pool, strlen(name)+1); + strcpy(lp->name, name); + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_obj_name - assign (change) objective function name +* +* SYNOPSIS +* +* void glp_set_obj_name(glp_prob *lp, const char *name); +* +* DESCRIPTION +* +* The routine glp_set_obj_name assigns a given symbolic name (1 up to +* 255 characters) to the objective function of the specified problem +* object. +* +* If the parameter name is NULL or empty string, the routine erases an +* existing name of the objective function. */ + +void glp_set_obj_name(glp_prob *lp, const char *name) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_obj_name: operation not allowed\n"); + if (lp->obj != NULL) + { dmp_free_atom(lp->pool, lp->obj, strlen(lp->obj)+1); + lp->obj = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int k; + for (k = 0; name[k] != '\0'; k++) + { if (k == 256) + xerror("glp_set_obj_name: objective name too long\n"); + if (iscntrl((unsigned char)name[k])) + xerror("glp_set_obj_name: objective name contains invali" + "d character(s)\n"); + } + lp->obj = dmp_get_atom(lp->pool, strlen(name)+1); + strcpy(lp->obj, name); + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_obj_dir - set (change) optimization direction flag +* +* SYNOPSIS +* +* void glp_set_obj_dir(glp_prob *lp, int dir); +* +* DESCRIPTION +* +* The routine glp_set_obj_dir sets (changes) optimization direction +* flag (i.e. "sense" of the objective function) as specified by the +* parameter dir: +* +* GLP_MIN - minimization; +* GLP_MAX - maximization. */ + +void glp_set_obj_dir(glp_prob *lp, int dir) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_obj_dir: operation not allowed\n"); + if (!(dir == GLP_MIN || dir == GLP_MAX)) + xerror("glp_set_obj_dir: dir = %d; invalid direction flag\n", + dir); + lp->dir = dir; + return; +} + +/*********************************************************************** +* NAME +* +* glp_add_rows - add new rows to problem object +* +* SYNOPSIS +* +* int glp_add_rows(glp_prob *lp, int nrs); +* +* DESCRIPTION +* +* The routine glp_add_rows adds nrs rows (constraints) to the specified +* problem object. New rows are always added to the end of the row list, +* so the ordinal numbers of existing rows remain unchanged. +* +* Being added each new row is initially free (unbounded) and has empty +* list of the constraint coefficients. +* +* RETURNS +* +* The routine glp_add_rows returns the ordinal number of the first new +* row added to the problem object. */ + +int glp_add_rows(glp_prob *lp, int nrs) +{ glp_tree *tree = lp->tree; + GLPROW *row; + int m_new, i; + /* determine new number of rows */ + if (nrs < 1) + xerror("glp_add_rows: nrs = %d; invalid number of rows\n", + nrs); + if (nrs > M_MAX - lp->m) + xerror("glp_add_rows: nrs = %d; too many rows\n", nrs); + m_new = lp->m + nrs; + /* increase the room, if necessary */ + if (lp->m_max < m_new) + { GLPROW **save = lp->row; + while (lp->m_max < m_new) + { lp->m_max += lp->m_max; + xassert(lp->m_max > 0); + } + lp->row = xcalloc(1+lp->m_max, sizeof(GLPROW *)); + memcpy(&lp->row[1], &save[1], lp->m * sizeof(GLPROW *)); + xfree(save); + /* do not forget about the basis header */ + xfree(lp->head); + lp->head = xcalloc(1+lp->m_max, sizeof(int)); + } + /* add new rows to the end of the row list */ + for (i = lp->m+1; i <= m_new; i++) + { /* create row descriptor */ + lp->row[i] = row = dmp_get_atom(lp->pool, sizeof(GLPROW)); + row->i = i; + row->name = NULL; + row->node = NULL; +#if 1 /* 20/IX-2008 */ + row->level = 0; + row->origin = 0; + row->klass = 0; + if (tree != NULL) + { switch (tree->reason) + { case 0: + break; + case GLP_IROWGEN: + xassert(tree->curr != NULL); + row->level = tree->curr->level; + row->origin = GLP_RF_LAZY; + break; + case GLP_ICUTGEN: + xassert(tree->curr != NULL); + row->level = tree->curr->level; + row->origin = GLP_RF_CUT; + break; + default: + xassert(tree != tree); + } + } +#endif + row->type = GLP_FR; + row->lb = row->ub = 0.0; + row->ptr = NULL; + row->rii = 1.0; + row->stat = GLP_BS; +#if 0 + row->bind = -1; +#else + row->bind = 0; +#endif + row->prim = row->dual = 0.0; + row->pval = row->dval = 0.0; + row->mipx = 0.0; + } + /* set new number of rows */ + lp->m = m_new; + /* invalidate the basis factorization */ + lp->valid = 0; +#if 1 + if (tree != NULL && tree->reason != 0) tree->reopt = 1; +#endif + /* return the ordinal number of the first row added */ + return m_new - nrs + 1; +} + +/*********************************************************************** +* NAME +* +* glp_add_cols - add new columns to problem object +* +* SYNOPSIS +* +* int glp_add_cols(glp_prob *lp, int ncs); +* +* DESCRIPTION +* +* The routine glp_add_cols adds ncs columns (structural variables) to +* the specified problem object. New columns are always added to the end +* of the column list, so the ordinal numbers of existing columns remain +* unchanged. +* +* Being added each new column is initially fixed at zero and has empty +* list of the constraint coefficients. +* +* RETURNS +* +* The routine glp_add_cols returns the ordinal number of the first new +* column added to the problem object. */ + +int glp_add_cols(glp_prob *lp, int ncs) +{ glp_tree *tree = lp->tree; + GLPCOL *col; + int n_new, j; + if (tree != NULL && tree->reason != 0) + xerror("glp_add_cols: operation not allowed\n"); + /* determine new number of columns */ + if (ncs < 1) + xerror("glp_add_cols: ncs = %d; invalid number of columns\n", + ncs); + if (ncs > N_MAX - lp->n) + xerror("glp_add_cols: ncs = %d; too many columns\n", ncs); + n_new = lp->n + ncs; + /* increase the room, if necessary */ + if (lp->n_max < n_new) + { GLPCOL **save = lp->col; + while (lp->n_max < n_new) + { lp->n_max += lp->n_max; + xassert(lp->n_max > 0); + } + lp->col = xcalloc(1+lp->n_max, sizeof(GLPCOL *)); + memcpy(&lp->col[1], &save[1], lp->n * sizeof(GLPCOL *)); + xfree(save); + } + /* add new columns to the end of the column list */ + for (j = lp->n+1; j <= n_new; j++) + { /* create column descriptor */ + lp->col[j] = col = dmp_get_atom(lp->pool, sizeof(GLPCOL)); + col->j = j; + col->name = NULL; + col->node = NULL; + col->kind = GLP_CV; + col->type = GLP_FX; + col->lb = col->ub = 0.0; + col->coef = 0.0; + col->ptr = NULL; + col->sjj = 1.0; + col->stat = GLP_NS; +#if 0 + col->bind = -1; +#else + col->bind = 0; /* the basis may remain valid */ +#endif + col->prim = col->dual = 0.0; + col->pval = col->dval = 0.0; + col->mipx = 0.0; + } + /* set new number of columns */ + lp->n = n_new; + /* return the ordinal number of the first column added */ + return n_new - ncs + 1; +} + +/*********************************************************************** +* NAME +* +* glp_set_row_name - assign (change) row name +* +* SYNOPSIS +* +* void glp_set_row_name(glp_prob *lp, int i, const char *name); +* +* DESCRIPTION +* +* The routine glp_set_row_name assigns a given symbolic name (1 up to +* 255 characters) to i-th row (auxiliary variable) of the specified +* problem object. +* +* If the parameter name is NULL or empty string, the routine erases an +* existing name of i-th row. */ + +void glp_set_row_name(glp_prob *lp, int i, const char *name) +{ glp_tree *tree = lp->tree; + GLPROW *row; + if (!(1 <= i && i <= lp->m)) + xerror("glp_set_row_name: i = %d; row number out of range\n", + i); + row = lp->row[i]; + if (tree != NULL && tree->reason != 0) + { xassert(tree->curr != NULL); + xassert(row->level == tree->curr->level); + } + if (row->name != NULL) + { if (row->node != NULL) + { xassert(lp->r_tree != NULL); + avl_delete_node(lp->r_tree, row->node); + row->node = NULL; + } + dmp_free_atom(lp->pool, row->name, strlen(row->name)+1); + row->name = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int k; + for (k = 0; name[k] != '\0'; k++) + { if (k == 256) + xerror("glp_set_row_name: i = %d; row name too long\n", + i); + if (iscntrl((unsigned char)name[k])) + xerror("glp_set_row_name: i = %d: row name contains inva" + "lid character(s)\n", i); + } + row->name = dmp_get_atom(lp->pool, strlen(name)+1); + strcpy(row->name, name); + if (lp->r_tree != NULL) + { xassert(row->node == NULL); + row->node = avl_insert_node(lp->r_tree, row->name); + avl_set_node_link(row->node, row); + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_col_name - assign (change) column name +* +* SYNOPSIS +* +* void glp_set_col_name(glp_prob *lp, int j, const char *name); +* +* DESCRIPTION +* +* The routine glp_set_col_name assigns a given symbolic name (1 up to +* 255 characters) to j-th column (structural variable) of the specified +* problem object. +* +* If the parameter name is NULL or empty string, the routine erases an +* existing name of j-th column. */ + +void glp_set_col_name(glp_prob *lp, int j, const char *name) +{ glp_tree *tree = lp->tree; + GLPCOL *col; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_col_name: operation not allowed\n"); + if (!(1 <= j && j <= lp->n)) + xerror("glp_set_col_name: j = %d; column number out of range\n" + , j); + col = lp->col[j]; + if (col->name != NULL) + { if (col->node != NULL) + { xassert(lp->c_tree != NULL); + avl_delete_node(lp->c_tree, col->node); + col->node = NULL; + } + dmp_free_atom(lp->pool, col->name, strlen(col->name)+1); + col->name = NULL; + } + if (!(name == NULL || name[0] == '\0')) + { int k; + for (k = 0; name[k] != '\0'; k++) + { if (k == 256) + xerror("glp_set_col_name: j = %d; column name too long\n" + , j); + if (iscntrl((unsigned char)name[k])) + xerror("glp_set_col_name: j = %d: column name contains i" + "nvalid character(s)\n", j); + } + col->name = dmp_get_atom(lp->pool, strlen(name)+1); + strcpy(col->name, name); + if (lp->c_tree != NULL && col->name != NULL) + { xassert(col->node == NULL); + col->node = avl_insert_node(lp->c_tree, col->name); + avl_set_node_link(col->node, col); + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_row_bnds - set (change) row bounds +* +* SYNOPSIS +* +* void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, +* double ub); +* +* DESCRIPTION +* +* The routine glp_set_row_bnds sets (changes) the type and bounds of +* i-th row (auxiliary variable) of the specified problem object. +* +* Parameters type, lb, and ub specify the type, lower bound, and upper +* bound, respectively, as follows: +* +* Type Bounds Comments +* ------------------------------------------------------ +* GLP_FR -inf < x < +inf Free variable +* GLP_LO lb <= x < +inf Variable with lower bound +* GLP_UP -inf < x <= ub Variable with upper bound +* GLP_DB lb <= x <= ub Double-bounded variable +* GLP_FX x = lb Fixed variable +* +* where x is the auxiliary variable associated with i-th row. +* +* If the row has no lower bound, the parameter lb is ignored. If the +* row has no upper bound, the parameter ub is ignored. If the row is +* an equality constraint (i.e. the corresponding auxiliary variable is +* of fixed type), only the parameter lb is used while the parameter ub +* is ignored. */ + +void glp_set_row_bnds(glp_prob *lp, int i, int type, double lb, + double ub) +{ GLPROW *row; + if (!(1 <= i && i <= lp->m)) + xerror("glp_set_row_bnds: i = %d; row number out of range\n", + i); + row = lp->row[i]; + row->type = type; + switch (type) + { case GLP_FR: + row->lb = row->ub = 0.0; + if (row->stat != GLP_BS) row->stat = GLP_NF; + break; + case GLP_LO: + row->lb = lb, row->ub = 0.0; + if (row->stat != GLP_BS) row->stat = GLP_NL; + break; + case GLP_UP: + row->lb = 0.0, row->ub = ub; + if (row->stat != GLP_BS) row->stat = GLP_NU; + break; + case GLP_DB: + row->lb = lb, row->ub = ub; + if (!(row->stat == GLP_BS || + row->stat == GLP_NL || row->stat == GLP_NU)) + row->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); + break; + case GLP_FX: + row->lb = row->ub = lb; + if (row->stat != GLP_BS) row->stat = GLP_NS; + break; + default: + xerror("glp_set_row_bnds: i = %d; type = %d; invalid row ty" + "pe\n", i, type); + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_col_bnds - set (change) column bounds +* +* SYNOPSIS +* +* void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, +* double ub); +* +* DESCRIPTION +* +* The routine glp_set_col_bnds sets (changes) the type and bounds of +* j-th column (structural variable) of the specified problem object. +* +* Parameters type, lb, and ub specify the type, lower bound, and upper +* bound, respectively, as follows: +* +* Type Bounds Comments +* ------------------------------------------------------ +* GLP_FR -inf < x < +inf Free variable +* GLP_LO lb <= x < +inf Variable with lower bound +* GLP_UP -inf < x <= ub Variable with upper bound +* GLP_DB lb <= x <= ub Double-bounded variable +* GLP_FX x = lb Fixed variable +* +* where x is the structural variable associated with j-th column. +* +* If the column has no lower bound, the parameter lb is ignored. If the +* column has no upper bound, the parameter ub is ignored. If the column +* is of fixed type, only the parameter lb is used while the parameter +* ub is ignored. */ + +void glp_set_col_bnds(glp_prob *lp, int j, int type, double lb, + double ub) +{ GLPCOL *col; + if (!(1 <= j && j <= lp->n)) + xerror("glp_set_col_bnds: j = %d; column number out of range\n" + , j); + col = lp->col[j]; + col->type = type; + switch (type) + { case GLP_FR: + col->lb = col->ub = 0.0; + if (col->stat != GLP_BS) col->stat = GLP_NF; + break; + case GLP_LO: + col->lb = lb, col->ub = 0.0; + if (col->stat != GLP_BS) col->stat = GLP_NL; + break; + case GLP_UP: + col->lb = 0.0, col->ub = ub; + if (col->stat != GLP_BS) col->stat = GLP_NU; + break; + case GLP_DB: + col->lb = lb, col->ub = ub; + if (!(col->stat == GLP_BS || + col->stat == GLP_NL || col->stat == GLP_NU)) + col->stat = (fabs(lb) <= fabs(ub) ? GLP_NL : GLP_NU); + break; + case GLP_FX: + col->lb = col->ub = lb; + if (col->stat != GLP_BS) col->stat = GLP_NS; + break; + default: + xerror("glp_set_col_bnds: j = %d; type = %d; invalid column" + " type\n", j, type); + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_obj_coef - set (change) obj. coefficient or constant term +* +* SYNOPSIS +* +* void glp_set_obj_coef(glp_prob *lp, int j, double coef); +* +* DESCRIPTION +* +* The routine glp_set_obj_coef sets (changes) objective coefficient at +* j-th column (structural variable) of the specified problem object. +* +* If the parameter j is 0, the routine sets (changes) the constant term +* ("shift") of the objective function. */ + +void glp_set_obj_coef(glp_prob *lp, int j, double coef) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_obj_coef: operation not allowed\n"); + if (!(0 <= j && j <= lp->n)) + xerror("glp_set_obj_coef: j = %d; column number out of range\n" + , j); + if (j == 0) + lp->c0 = coef; + else + lp->col[j]->coef = coef; + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_mat_row - set (replace) row of the constraint matrix +* +* SYNOPSIS +* +* void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], +* const double val[]); +* +* DESCRIPTION +* +* The routine glp_set_mat_row stores (replaces) the contents of i-th +* row of the constraint matrix of the specified problem object. +* +* Column indices and numeric values of new row elements must be placed +* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where +* 0 <= len <= n is the new length of i-th row, n is the current number +* of columns in the problem object. Elements with identical column +* indices are not allowed. Zero elements are allowed, but they are not +* stored in the constraint matrix. +* +* If the parameter len is zero, the parameters ind and/or val can be +* specified as NULL. */ + +void glp_set_mat_row(glp_prob *lp, int i, int len, const int ind[], + const double val[]) +{ glp_tree *tree = lp->tree; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij, *next; + int j, k; + /* obtain pointer to i-th row */ + if (!(1 <= i && i <= lp->m)) + xerror("glp_set_mat_row: i = %d; row number out of range\n", + i); + row = lp->row[i]; + if (tree != NULL && tree->reason != 0) + { xassert(tree->curr != NULL); + xassert(row->level == tree->curr->level); + } + /* remove all existing elements from i-th row */ + while (row->ptr != NULL) + { /* take next element in the row */ + aij = row->ptr; + /* remove the element from the row list */ + row->ptr = aij->r_next; + /* obtain pointer to corresponding column */ + col = aij->col; + /* remove the element from the column list */ + if (aij->c_prev == NULL) + col->ptr = aij->c_next; + else + aij->c_prev->c_next = aij->c_next; + if (aij->c_next == NULL) + ; + else + aij->c_next->c_prev = aij->c_prev; + /* return the element to the memory pool */ + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + /* if the corresponding column is basic, invalidate the basis + factorization */ + if (col->stat == GLP_BS) lp->valid = 0; + } + /* store new contents of i-th row */ + if (!(0 <= len && len <= lp->n)) + xerror("glp_set_mat_row: i = %d; len = %d; invalid row length " + "\n", i, len); + if (len > NNZ_MAX - lp->nnz) + xerror("glp_set_mat_row: i = %d; len = %d; too many constraint" + " coefficients\n", i, len); + for (k = 1; k <= len; k++) + { /* take number j of corresponding column */ + j = ind[k]; + /* obtain pointer to j-th column */ + if (!(1 <= j && j <= lp->n)) + xerror("glp_set_mat_row: i = %d; ind[%d] = %d; column index" + " out of range\n", i, k, j); + col = lp->col[j]; + /* if there is element with the same column index, it can only + be found in the beginning of j-th column list */ + if (col->ptr != NULL && col->ptr->row->i == i) + xerror("glp_set_mat_row: i = %d; ind[%d] = %d; duplicate co" + "lumn indices not allowed\n", i, k, j); + /* create new element */ + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; + aij->row = row; + aij->col = col; + aij->val = val[k]; + /* add the new element to the beginning of i-th row and j-th + column lists */ + aij->r_prev = NULL; + aij->r_next = row->ptr; + aij->c_prev = NULL; + aij->c_next = col->ptr; + if (aij->r_next != NULL) aij->r_next->r_prev = aij; + if (aij->c_next != NULL) aij->c_next->c_prev = aij; + row->ptr = col->ptr = aij; + /* if the corresponding column is basic, invalidate the basis + factorization */ + if (col->stat == GLP_BS && aij->val != 0.0) lp->valid = 0; + } + /* remove zero elements from i-th row */ + for (aij = row->ptr; aij != NULL; aij = next) + { next = aij->r_next; + if (aij->val == 0.0) + { /* remove the element from the row list */ + if (aij->r_prev == NULL) + row->ptr = next; + else + aij->r_prev->r_next = next; + if (next == NULL) + ; + else + next->r_prev = aij->r_prev; + /* remove the element from the column list */ + xassert(aij->c_prev == NULL); + aij->col->ptr = aij->c_next; + if (aij->c_next != NULL) aij->c_next->c_prev = NULL; + /* return the element to the memory pool */ + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_mat_col - set (replace) column of the constraint matrix +* +* SYNOPSIS +* +* void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], +* const double val[]); +* +* DESCRIPTION +* +* The routine glp_set_mat_col stores (replaces) the contents of j-th +* column of the constraint matrix of the specified problem object. +* +* Row indices and numeric values of new column elements must be placed +* in locations ind[1], ..., ind[len] and val[1], ..., val[len], where +* 0 <= len <= m is the new length of j-th column, m is the current +* number of rows in the problem object. Elements with identical column +* indices are not allowed. Zero elements are allowed, but they are not +* stored in the constraint matrix. +* +* If the parameter len is zero, the parameters ind and/or val can be +* specified as NULL. */ + +void glp_set_mat_col(glp_prob *lp, int j, int len, const int ind[], + const double val[]) +{ glp_tree *tree = lp->tree; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij, *next; + int i, k; + if (tree != NULL && tree->reason != 0) + xerror("glp_set_mat_col: operation not allowed\n"); + /* obtain pointer to j-th column */ + if (!(1 <= j && j <= lp->n)) + xerror("glp_set_mat_col: j = %d; column number out of range\n", + j); + col = lp->col[j]; + /* remove all existing elements from j-th column */ + while (col->ptr != NULL) + { /* take next element in the column */ + aij = col->ptr; + /* remove the element from the column list */ + col->ptr = aij->c_next; + /* obtain pointer to corresponding row */ + row = aij->row; + /* remove the element from the row list */ + if (aij->r_prev == NULL) + row->ptr = aij->r_next; + else + aij->r_prev->r_next = aij->r_next; + if (aij->r_next == NULL) + ; + else + aij->r_next->r_prev = aij->r_prev; + /* return the element to the memory pool */ + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + } + /* store new contents of j-th column */ + if (!(0 <= len && len <= lp->m)) + xerror("glp_set_mat_col: j = %d; len = %d; invalid column leng" + "th\n", j, len); + if (len > NNZ_MAX - lp->nnz) + xerror("glp_set_mat_col: j = %d; len = %d; too many constraint" + " coefficients\n", j, len); + for (k = 1; k <= len; k++) + { /* take number i of corresponding row */ + i = ind[k]; + /* obtain pointer to i-th row */ + if (!(1 <= i && i <= lp->m)) + xerror("glp_set_mat_col: j = %d; ind[%d] = %d; row index ou" + "t of range\n", j, k, i); + row = lp->row[i]; + /* if there is element with the same row index, it can only be + found in the beginning of i-th row list */ + if (row->ptr != NULL && row->ptr->col->j == j) + xerror("glp_set_mat_col: j = %d; ind[%d] = %d; duplicate ro" + "w indices not allowed\n", j, k, i); + /* create new element */ + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; + aij->row = row; + aij->col = col; + aij->val = val[k]; + /* add the new element to the beginning of i-th row and j-th + column lists */ + aij->r_prev = NULL; + aij->r_next = row->ptr; + aij->c_prev = NULL; + aij->c_next = col->ptr; + if (aij->r_next != NULL) aij->r_next->r_prev = aij; + if (aij->c_next != NULL) aij->c_next->c_prev = aij; + row->ptr = col->ptr = aij; + } + /* remove zero elements from j-th column */ + for (aij = col->ptr; aij != NULL; aij = next) + { next = aij->c_next; + if (aij->val == 0.0) + { /* remove the element from the row list */ + xassert(aij->r_prev == NULL); + aij->row->ptr = aij->r_next; + if (aij->r_next != NULL) aij->r_next->r_prev = NULL; + /* remove the element from the column list */ + if (aij->c_prev == NULL) + col->ptr = next; + else + aij->c_prev->c_next = next; + if (next == NULL) + ; + else + next->c_prev = aij->c_prev; + /* return the element to the memory pool */ + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + } + } + /* if j-th column is basic, invalidate the basis factorization */ + if (col->stat == GLP_BS) lp->valid = 0; + return; +} + +/*********************************************************************** +* NAME +* +* glp_load_matrix - load (replace) the whole constraint matrix +* +* SYNOPSIS +* +* void glp_load_matrix(glp_prob *lp, int ne, const int ia[], +* const int ja[], const double ar[]); +* +* DESCRIPTION +* +* The routine glp_load_matrix loads the constraint matrix passed in +* the arrays ia, ja, and ar into the specified problem object. Before +* loading the current contents of the constraint matrix is destroyed. +* +* Constraint coefficients (elements of the constraint matrix) must be +* specified as triplets (ia[k], ja[k], ar[k]) for k = 1, ..., ne, +* where ia[k] is the row index, ja[k] is the column index, ar[k] is a +* numeric value of corresponding constraint coefficient. The parameter +* ne specifies the total number of (non-zero) elements in the matrix +* to be loaded. Coefficients with identical indices are not allowed. +* Zero coefficients are allowed, however, they are not stored in the +* constraint matrix. +* +* If the parameter ne is zero, the parameters ia, ja, and ar can be +* specified as NULL. */ + +void glp_load_matrix(glp_prob *lp, int ne, const int ia[], + const int ja[], const double ar[]) +{ glp_tree *tree = lp->tree; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij, *next; + int i, j, k; + if (tree != NULL && tree->reason != 0) + xerror("glp_load_matrix: operation not allowed\n"); + /* clear the constraint matrix */ + for (i = 1; i <= lp->m; i++) + { row = lp->row[i]; + while (row->ptr != NULL) + { aij = row->ptr; + row->ptr = aij->r_next; + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + } + } + xassert(lp->nnz == 0); + for (j = 1; j <= lp->n; j++) lp->col[j]->ptr = NULL; + /* load the new contents of the constraint matrix and build its + row lists */ + if (ne < 0) + xerror("glp_load_matrix: ne = %d; invalid number of constraint" + " coefficients\n", ne); + if (ne > NNZ_MAX) + xerror("glp_load_matrix: ne = %d; too many constraint coeffici" + "ents\n", ne); + for (k = 1; k <= ne; k++) + { /* take indices of new element */ + i = ia[k], j = ja[k]; + /* obtain pointer to i-th row */ + if (!(1 <= i && i <= lp->m)) + xerror("glp_load_matrix: ia[%d] = %d; row index out of rang" + "e\n", k, i); + row = lp->row[i]; + /* obtain pointer to j-th column */ + if (!(1 <= j && j <= lp->n)) + xerror("glp_load_matrix: ja[%d] = %d; column index out of r" + "ange\n", k, j); + col = lp->col[j]; + /* create new element */ + aij = dmp_get_atom(lp->pool, sizeof(GLPAIJ)), lp->nnz++; + aij->row = row; + aij->col = col; + aij->val = ar[k]; + /* add the new element to the beginning of i-th row list */ + aij->r_prev = NULL; + aij->r_next = row->ptr; + if (aij->r_next != NULL) aij->r_next->r_prev = aij; + row->ptr = aij; + } + xassert(lp->nnz == ne); + /* build column lists of the constraint matrix and check elements + with identical indices */ + for (i = 1; i <= lp->m; i++) + { for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) + { /* obtain pointer to corresponding column */ + col = aij->col; + /* if there is element with identical indices, it can only + be found in the beginning of j-th column list */ + if (col->ptr != NULL && col->ptr->row->i == i) + { for (k = 1; k <= ne; k++) + if (ia[k] == i && ja[k] == col->j) break; + xerror("glp_load_mat: ia[%d] = %d; ja[%d] = %d; duplicat" + "e indices not allowed\n", k, i, k, col->j); + } + /* add the element to the beginning of j-th column list */ + aij->c_prev = NULL; + aij->c_next = col->ptr; + if (aij->c_next != NULL) aij->c_next->c_prev = aij; + col->ptr = aij; + } + } + /* remove zero elements from the constraint matrix */ + for (i = 1; i <= lp->m; i++) + { row = lp->row[i]; + for (aij = row->ptr; aij != NULL; aij = next) + { next = aij->r_next; + if (aij->val == 0.0) + { /* remove the element from the row list */ + if (aij->r_prev == NULL) + row->ptr = next; + else + aij->r_prev->r_next = next; + if (next == NULL) + ; + else + next->r_prev = aij->r_prev; + /* remove the element from the column list */ + if (aij->c_prev == NULL) + aij->col->ptr = aij->c_next; + else + aij->c_prev->c_next = aij->c_next; + if (aij->c_next == NULL) + ; + else + aij->c_next->c_prev = aij->c_prev; + /* return the element to the memory pool */ + dmp_free_atom(lp->pool, aij, sizeof(GLPAIJ)), lp->nnz--; + } + } + } + /* invalidate the basis factorization */ + lp->valid = 0; + return; +} + +/*********************************************************************** +* NAME +* +* glp_check_dup - check for duplicate elements in sparse matrix +* +* SYNOPSIS +* +* int glp_check_dup(int m, int n, int ne, const int ia[], +* const int ja[]); +* +* DESCRIPTION +* +* The routine glp_check_dup checks for duplicate elements (that is, +* elements with identical indices) in a sparse matrix specified in the +* coordinate format. +* +* The parameters m and n specifies, respectively, the number of rows +* and columns in the matrix, m >= 0, n >= 0. +* +* The parameter ne specifies the number of (structurally) non-zero +* elements in the matrix, ne >= 0. +* +* Elements of the matrix are specified as doublets (ia[k],ja[k]) for +* k = 1,...,ne, where ia[k] is a row index, ja[k] is a column index. +* +* The routine glp_check_dup can be used prior to a call to the routine +* glp_load_matrix to check that the constraint matrix to be loaded has +* no duplicate elements. +* +* RETURNS +* +* The routine glp_check_dup returns one of the following values: +* +* 0 - the matrix has no duplicate elements; +* +* -k - indices ia[k] or/and ja[k] are out of range; +* +* +k - element (ia[k],ja[k]) is duplicate. */ + +int glp_check_dup(int m, int n, int ne, const int ia[], const int ja[]) +{ int i, j, k, *ptr, *next, ret; + char *flag; + if (m < 0) + xerror("glp_check_dup: m = %d; invalid parameter\n"); + if (n < 0) + xerror("glp_check_dup: n = %d; invalid parameter\n"); + if (ne < 0) + xerror("glp_check_dup: ne = %d; invalid parameter\n"); + if (ne > 0 && ia == NULL) + xerror("glp_check_dup: ia = %p; invalid parameter\n", ia); + if (ne > 0 && ja == NULL) + xerror("glp_check_dup: ja = %p; invalid parameter\n", ja); + for (k = 1; k <= ne; k++) + { i = ia[k], j = ja[k]; + if (!(1 <= i && i <= m && 1 <= j && j <= n)) + { ret = -k; + goto done; + } + } + if (m == 0 || n == 0) + { ret = 0; + goto done; + } + /* allocate working arrays */ + ptr = xcalloc(1+m, sizeof(int)); + next = xcalloc(1+ne, sizeof(int)); + flag = xcalloc(1+n, sizeof(char)); + /* build row lists */ + for (i = 1; i <= m; i++) + ptr[i] = 0; + for (k = 1; k <= ne; k++) + { i = ia[k]; + next[k] = ptr[i]; + ptr[i] = k; + } + /* clear column flags */ + for (j = 1; j <= n; j++) + flag[j] = 0; + /* check for duplicate elements */ + for (i = 1; i <= m; i++) + { for (k = ptr[i]; k != 0; k = next[k]) + { j = ja[k]; + if (flag[j]) + { /* find first element (i,j) */ + for (k = 1; k <= ne; k++) + if (ia[k] == i && ja[k] == j) break; + xassert(k <= ne); + /* find next (duplicate) element (i,j) */ + for (k++; k <= ne; k++) + if (ia[k] == i && ja[k] == j) break; + xassert(k <= ne); + ret = +k; + goto skip; + } + flag[j] = 1; + } + /* clear column flags */ + for (k = ptr[i]; k != 0; k = next[k]) + flag[ja[k]] = 0; + } + /* no duplicate element found */ + ret = 0; +skip: /* free working arrays */ + xfree(ptr); + xfree(next); + xfree(flag); +done: return ret; +} + +/*********************************************************************** +* NAME +* +* glp_sort_matrix - sort elements of the constraint matrix +* +* SYNOPSIS +* +* void glp_sort_matrix(glp_prob *P); +* +* DESCRIPTION +* +* The routine glp_sort_matrix sorts elements of the constraint matrix +* rebuilding its row and column linked lists. On exit from the routine +* the constraint matrix is not changed, however, elements in the row +* linked lists become ordered by ascending column indices, and the +* elements in the column linked lists become ordered by ascending row +* indices. */ + +void glp_sort_matrix(glp_prob *P) +{ GLPAIJ *aij; + int i, j; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_sort_matrix: P = %p; invalid problem object\n", + P); +#endif + /* rebuild row linked lists */ + for (i = P->m; i >= 1; i--) + P->row[i]->ptr = NULL; + for (j = P->n; j >= 1; j--) + { for (aij = P->col[j]->ptr; aij != NULL; aij = aij->c_next) + { i = aij->row->i; + aij->r_prev = NULL; + aij->r_next = P->row[i]->ptr; + if (aij->r_next != NULL) aij->r_next->r_prev = aij; + P->row[i]->ptr = aij; + } + } + /* rebuild column linked lists */ + for (j = P->n; j >= 1; j--) + P->col[j]->ptr = NULL; + for (i = P->m; i >= 1; i--) + { for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) + { j = aij->col->j; + aij->c_prev = NULL; + aij->c_next = P->col[j]->ptr; + if (aij->c_next != NULL) aij->c_next->c_prev = aij; + P->col[j]->ptr = aij; + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_del_rows - delete rows from problem object +* +* SYNOPSIS +* +* void glp_del_rows(glp_prob *lp, int nrs, const int num[]); +* +* DESCRIPTION +* +* The routine glp_del_rows deletes rows from the specified problem +* object. Ordinal numbers of rows to be deleted should be placed in +* locations num[1], ..., num[nrs], where nrs > 0. +* +* Note that deleting rows involves changing ordinal numbers of other +* rows remaining in the problem object. New ordinal numbers of the +* remaining rows are assigned under the assumption that the original +* order of rows is not changed. */ + +void glp_del_rows(glp_prob *lp, int nrs, const int num[]) +{ glp_tree *tree = lp->tree; + GLPROW *row; + int i, k, m_new; + /* mark rows to be deleted */ + if (!(1 <= nrs && nrs <= lp->m)) + xerror("glp_del_rows: nrs = %d; invalid number of rows\n", + nrs); + for (k = 1; k <= nrs; k++) + { /* take the number of row to be deleted */ + i = num[k]; + /* obtain pointer to i-th row */ + if (!(1 <= i && i <= lp->m)) + xerror("glp_del_rows: num[%d] = %d; row number out of range" + "\n", k, i); + row = lp->row[i]; + if (tree != NULL && tree->reason != 0) + { if (!(tree->reason == GLP_IROWGEN || + tree->reason == GLP_ICUTGEN)) + xerror("glp_del_rows: operation not allowed\n"); + xassert(tree->curr != NULL); + if (row->level != tree->curr->level) + xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" + "elete row created not in current subproblem\n", k,i); + if (row->stat != GLP_BS) + xerror("glp_del_rows: num[%d] = %d; invalid attempt to d" + "elete active row (constraint)\n", k, i); + tree->reinv = 1; + } + /* check that the row is not marked yet */ + if (row->i == 0) + xerror("glp_del_rows: num[%d] = %d; duplicate row numbers n" + "ot allowed\n", k, i); + /* erase symbolic name assigned to the row */ + glp_set_row_name(lp, i, NULL); + xassert(row->node == NULL); + /* erase corresponding row of the constraint matrix */ + glp_set_mat_row(lp, i, 0, NULL, NULL); + xassert(row->ptr == NULL); + /* mark the row to be deleted */ + row->i = 0; + } + /* delete all marked rows from the row list */ + m_new = 0; + for (i = 1; i <= lp->m; i++) + { /* obtain pointer to i-th row */ + row = lp->row[i]; + /* check if the row is marked */ + if (row->i == 0) + { /* it is marked, delete it */ + dmp_free_atom(lp->pool, row, sizeof(GLPROW)); + } + else + { /* it is not marked; keep it */ + row->i = ++m_new; + lp->row[row->i] = row; + } + } + /* set new number of rows */ + lp->m = m_new; + /* invalidate the basis factorization */ + lp->valid = 0; + return; +} + +/*********************************************************************** +* NAME +* +* glp_del_cols - delete columns from problem object +* +* SYNOPSIS +* +* void glp_del_cols(glp_prob *lp, int ncs, const int num[]); +* +* DESCRIPTION +* +* The routine glp_del_cols deletes columns from the specified problem +* object. Ordinal numbers of columns to be deleted should be placed in +* locations num[1], ..., num[ncs], where ncs > 0. +* +* Note that deleting columns involves changing ordinal numbers of +* other columns remaining in the problem object. New ordinal numbers +* of the remaining columns are assigned under the assumption that the +* original order of columns is not changed. */ + +void glp_del_cols(glp_prob *lp, int ncs, const int num[]) +{ glp_tree *tree = lp->tree; + GLPCOL *col; + int j, k, n_new; + if (tree != NULL && tree->reason != 0) + xerror("glp_del_cols: operation not allowed\n"); + /* mark columns to be deleted */ + if (!(1 <= ncs && ncs <= lp->n)) + xerror("glp_del_cols: ncs = %d; invalid number of columns\n", + ncs); + for (k = 1; k <= ncs; k++) + { /* take the number of column to be deleted */ + j = num[k]; + /* obtain pointer to j-th column */ + if (!(1 <= j && j <= lp->n)) + xerror("glp_del_cols: num[%d] = %d; column number out of ra" + "nge", k, j); + col = lp->col[j]; + /* check that the column is not marked yet */ + if (col->j == 0) + xerror("glp_del_cols: num[%d] = %d; duplicate column number" + "s not allowed\n", k, j); + /* erase symbolic name assigned to the column */ + glp_set_col_name(lp, j, NULL); + xassert(col->node == NULL); + /* erase corresponding column of the constraint matrix */ + glp_set_mat_col(lp, j, 0, NULL, NULL); + xassert(col->ptr == NULL); + /* mark the column to be deleted */ + col->j = 0; + /* if it is basic, invalidate the basis factorization */ + if (col->stat == GLP_BS) lp->valid = 0; + } + /* delete all marked columns from the column list */ + n_new = 0; + for (j = 1; j <= lp->n; j++) + { /* obtain pointer to j-th column */ + col = lp->col[j]; + /* check if the column is marked */ + if (col->j == 0) + { /* it is marked; delete it */ + dmp_free_atom(lp->pool, col, sizeof(GLPCOL)); + } + else + { /* it is not marked; keep it */ + col->j = ++n_new; + lp->col[col->j] = col; + } + } + /* set new number of columns */ + lp->n = n_new; + /* if the basis header is still valid, adjust it */ + if (lp->valid) + { int m = lp->m; + int *head = lp->head; + for (j = 1; j <= n_new; j++) + { k = lp->col[j]->bind; + if (k != 0) + { xassert(1 <= k && k <= m); + head[k] = m + j; + } + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_copy_prob - copy problem object content +* +* SYNOPSIS +* +* void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names); +* +* DESCRIPTION +* +* The routine glp_copy_prob copies the content of the problem object +* prob to the problem object dest. +* +* The parameter names is a flag. If it is non-zero, the routine also +* copies all symbolic names; otherwise, if it is zero, symbolic names +* are not copied. */ + +void glp_copy_prob(glp_prob *dest, glp_prob *prob, int names) +{ glp_tree *tree = dest->tree; + glp_bfcp bfcp; + int i, j, len, *ind; + double *val; + if (tree != NULL && tree->reason != 0) + xerror("glp_copy_prob: operation not allowed\n"); + if (dest == prob) + xerror("glp_copy_prob: copying problem object to itself not al" + "lowed\n"); + if (!(names == GLP_ON || names == GLP_OFF)) + xerror("glp_copy_prob: names = %d; invalid parameter\n", + names); + glp_erase_prob(dest); + if (names && prob->name != NULL) + glp_set_prob_name(dest, prob->name); + if (names && prob->obj != NULL) + glp_set_obj_name(dest, prob->obj); + dest->dir = prob->dir; + dest->c0 = prob->c0; + if (prob->m > 0) + glp_add_rows(dest, prob->m); + if (prob->n > 0) + glp_add_cols(dest, prob->n); + glp_get_bfcp(prob, &bfcp); + glp_set_bfcp(dest, &bfcp); + dest->pbs_stat = prob->pbs_stat; + dest->dbs_stat = prob->dbs_stat; + dest->obj_val = prob->obj_val; + dest->some = prob->some; + dest->ipt_stat = prob->ipt_stat; + dest->ipt_obj = prob->ipt_obj; + dest->mip_stat = prob->mip_stat; + dest->mip_obj = prob->mip_obj; + for (i = 1; i <= prob->m; i++) + { GLPROW *to = dest->row[i]; + GLPROW *from = prob->row[i]; + if (names && from->name != NULL) + glp_set_row_name(dest, i, from->name); + to->type = from->type; + to->lb = from->lb; + to->ub = from->ub; + to->rii = from->rii; + to->stat = from->stat; + to->prim = from->prim; + to->dual = from->dual; + to->pval = from->pval; + to->dval = from->dval; + to->mipx = from->mipx; + } + ind = xcalloc(1+prob->m, sizeof(int)); + val = xcalloc(1+prob->m, sizeof(double)); + for (j = 1; j <= prob->n; j++) + { GLPCOL *to = dest->col[j]; + GLPCOL *from = prob->col[j]; + if (names && from->name != NULL) + glp_set_col_name(dest, j, from->name); + to->kind = from->kind; + to->type = from->type; + to->lb = from->lb; + to->ub = from->ub; + to->coef = from->coef; + len = glp_get_mat_col(prob, j, ind, val); + glp_set_mat_col(dest, j, len, ind, val); + to->sjj = from->sjj; + to->stat = from->stat; + to->prim = from->prim; + to->dual = from->dual; + to->pval = from->pval; + to->dval = from->dval; + to->mipx = from->mipx; + } + xfree(ind); + xfree(val); + return; +} + +/*********************************************************************** +* NAME +* +* glp_erase_prob - erase problem object content +* +* SYNOPSIS +* +* void glp_erase_prob(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_erase_prob erases the content of the specified +* problem object. The effect of this operation is the same as if the +* problem object would be deleted with the routine glp_delete_prob and +* then created anew with the routine glp_create_prob, with exception +* that the handle (pointer) to the problem object remains valid. */ + +static void delete_prob(glp_prob *lp); + +void glp_erase_prob(glp_prob *lp) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_erase_prob: operation not allowed\n"); + delete_prob(lp); + create_prob(lp); + return; +} + +/*********************************************************************** +* NAME +* +* glp_delete_prob - delete problem object +* +* SYNOPSIS +* +* void glp_delete_prob(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_delete_prob deletes the specified problem object and +* frees all the memory allocated to it. */ + +static void delete_prob(glp_prob *lp) +#if 0 /* 04/IV-2016 */ +{ lp->magic = 0x3F3F3F3F; +#else +{ +#endif + dmp_delete_pool(lp->pool); +#if 0 /* 08/III-2014 */ +#if 0 /* 17/XI-2009 */ + xfree(lp->cps); +#else + if (lp->parms != NULL) xfree(lp->parms); +#endif +#endif + xassert(lp->tree == NULL); +#if 0 + if (lp->cwa != NULL) xfree(lp->cwa); +#endif + xfree(lp->row); + xfree(lp->col); + if (lp->r_tree != NULL) avl_delete_tree(lp->r_tree); + if (lp->c_tree != NULL) avl_delete_tree(lp->c_tree); + xfree(lp->head); +#if 0 /* 08/III-2014 */ + if (lp->bfcp != NULL) xfree(lp->bfcp); +#endif + if (lp->bfd != NULL) bfd_delete_it(lp->bfd); + return; +} + +void glp_delete_prob(glp_prob *lp) +{ glp_tree *tree = lp->tree; + if (tree != NULL && tree->reason != 0) + xerror("glp_delete_prob: operation not allowed\n"); + delete_prob(lp); + xfree(lp); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob2.c b/glpk-5.0/src/api/prob2.c new file mode 100644 index 0000000..f54a803 --- /dev/null +++ b/glpk-5.0/src/api/prob2.c @@ -0,0 +1,489 @@ +/* prob2.c (problem retrieving routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2013 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_get_prob_name - retrieve problem name +* +* SYNOPSIS +* +* const char *glp_get_prob_name(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_prob_name returns a pointer to an internal +* buffer, which contains symbolic name of the problem. However, if the +* problem has no assigned name, the routine returns NULL. */ + +const char *glp_get_prob_name(glp_prob *lp) +{ char *name; + name = lp->name; + return name; +} + +/*********************************************************************** +* NAME +* +* glp_get_obj_name - retrieve objective function name +* +* SYNOPSIS +* +* const char *glp_get_obj_name(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_obj_name returns a pointer to an internal +* buffer, which contains a symbolic name of the objective function. +* However, if the objective function has no assigned name, the routine +* returns NULL. */ + +const char *glp_get_obj_name(glp_prob *lp) +{ char *name; + name = lp->obj; + return name; +} + +/*********************************************************************** +* NAME +* +* glp_get_obj_dir - retrieve optimization direction flag +* +* SYNOPSIS +* +* int glp_get_obj_dir(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_obj_dir returns the optimization direction flag +* (i.e. "sense" of the objective function): +* +* GLP_MIN - minimization; +* GLP_MAX - maximization. */ + +int glp_get_obj_dir(glp_prob *lp) +{ int dir = lp->dir; + return dir; +} + +/*********************************************************************** +* NAME +* +* glp_get_num_rows - retrieve number of rows +* +* SYNOPSIS +* +* int glp_get_num_rows(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_num_rows returns the current number of rows in +* the specified problem object. */ + +int glp_get_num_rows(glp_prob *lp) +{ int m = lp->m; + return m; +} + +/*********************************************************************** +* NAME +* +* glp_get_num_cols - retrieve number of columns +* +* SYNOPSIS +* +* int glp_get_num_cols(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_num_cols returns the current number of columns +* in the specified problem object. */ + +int glp_get_num_cols(glp_prob *lp) +{ int n = lp->n; + return n; +} + +/*********************************************************************** +* NAME +* +* glp_get_row_name - retrieve row name +* +* SYNOPSIS +* +* const char *glp_get_row_name(glp_prob *lp, int i); +* +* RETURNS +* +* The routine glp_get_row_name returns a pointer to an internal +* buffer, which contains symbolic name of i-th row. However, if i-th +* row has no assigned name, the routine returns NULL. */ + +const char *glp_get_row_name(glp_prob *lp, int i) +{ char *name; + if (!(1 <= i && i <= lp->m)) + xerror("glp_get_row_name: i = %d; row number out of range\n", + i); + name = lp->row[i]->name; + return name; +} + +/*********************************************************************** +* NAME +* +* glp_get_col_name - retrieve column name +* +* SYNOPSIS +* +* const char *glp_get_col_name(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_col_name returns a pointer to an internal +* buffer, which contains symbolic name of j-th column. However, if j-th +* column has no assigned name, the routine returns NULL. */ + +const char *glp_get_col_name(glp_prob *lp, int j) +{ char *name; + if (!(1 <= j && j <= lp->n)) + xerror("glp_get_col_name: j = %d; column number out of range\n" + , j); + name = lp->col[j]->name; + return name; +} + +/*********************************************************************** +* NAME +* +* glp_get_row_type - retrieve row type +* +* SYNOPSIS +* +* int glp_get_row_type(glp_prob *lp, int i); +* +* RETURNS +* +* The routine glp_get_row_type returns the type of i-th row, i.e. the +* type of corresponding auxiliary variable, as follows: +* +* GLP_FR - free (unbounded) variable; +* GLP_LO - variable with lower bound; +* GLP_UP - variable with upper bound; +* GLP_DB - double-bounded variable; +* GLP_FX - fixed variable. */ + +int glp_get_row_type(glp_prob *lp, int i) +{ if (!(1 <= i && i <= lp->m)) + xerror("glp_get_row_type: i = %d; row number out of range\n", + i); + return lp->row[i]->type; +} + +/*********************************************************************** +* NAME +* +* glp_get_row_lb - retrieve row lower bound +* +* SYNOPSIS +* +* double glp_get_row_lb(glp_prob *lp, int i); +* +* RETURNS +* +* The routine glp_get_row_lb returns the lower bound of i-th row, i.e. +* the lower bound of corresponding auxiliary variable. However, if the +* row has no lower bound, the routine returns -DBL_MAX. */ + +double glp_get_row_lb(glp_prob *lp, int i) +{ double lb; + if (!(1 <= i && i <= lp->m)) + xerror("glp_get_row_lb: i = %d; row number out of range\n", i); + switch (lp->row[i]->type) + { case GLP_FR: + case GLP_UP: + lb = -DBL_MAX; break; + case GLP_LO: + case GLP_DB: + case GLP_FX: + lb = lp->row[i]->lb; break; + default: + xassert(lp != lp); + } + return lb; +} + +/*********************************************************************** +* NAME +* +* glp_get_row_ub - retrieve row upper bound +* +* SYNOPSIS +* +* double glp_get_row_ub(glp_prob *lp, int i); +* +* RETURNS +* +* The routine glp_get_row_ub returns the upper bound of i-th row, i.e. +* the upper bound of corresponding auxiliary variable. However, if the +* row has no upper bound, the routine returns +DBL_MAX. */ + +double glp_get_row_ub(glp_prob *lp, int i) +{ double ub; + if (!(1 <= i && i <= lp->m)) + xerror("glp_get_row_ub: i = %d; row number out of range\n", i); + switch (lp->row[i]->type) + { case GLP_FR: + case GLP_LO: + ub = +DBL_MAX; break; + case GLP_UP: + case GLP_DB: + case GLP_FX: + ub = lp->row[i]->ub; break; + default: + xassert(lp != lp); + } + return ub; +} + +/*********************************************************************** +* NAME +* +* glp_get_col_type - retrieve column type +* +* SYNOPSIS +* +* int glp_get_col_type(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_col_type returns the type of j-th column, i.e. +* the type of corresponding structural variable, as follows: +* +* GLP_FR - free (unbounded) variable; +* GLP_LO - variable with lower bound; +* GLP_UP - variable with upper bound; +* GLP_DB - double-bounded variable; +* GLP_FX - fixed variable. */ + +int glp_get_col_type(glp_prob *lp, int j) +{ if (!(1 <= j && j <= lp->n)) + xerror("glp_get_col_type: j = %d; column number out of range\n" + , j); + return lp->col[j]->type; +} + +/*********************************************************************** +* NAME +* +* glp_get_col_lb - retrieve column lower bound +* +* SYNOPSIS +* +* double glp_get_col_lb(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_col_lb returns the lower bound of j-th column, +* i.e. the lower bound of corresponding structural variable. However, +* if the column has no lower bound, the routine returns -DBL_MAX. */ + +double glp_get_col_lb(glp_prob *lp, int j) +{ double lb; + if (!(1 <= j && j <= lp->n)) + xerror("glp_get_col_lb: j = %d; column number out of range\n", + j); + switch (lp->col[j]->type) + { case GLP_FR: + case GLP_UP: + lb = -DBL_MAX; break; + case GLP_LO: + case GLP_DB: + case GLP_FX: + lb = lp->col[j]->lb; break; + default: + xassert(lp != lp); + } + return lb; +} + +/*********************************************************************** +* NAME +* +* glp_get_col_ub - retrieve column upper bound +* +* SYNOPSIS +* +* double glp_get_col_ub(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_col_ub returns the upper bound of j-th column, +* i.e. the upper bound of corresponding structural variable. However, +* if the column has no upper bound, the routine returns +DBL_MAX. */ + +double glp_get_col_ub(glp_prob *lp, int j) +{ double ub; + if (!(1 <= j && j <= lp->n)) + xerror("glp_get_col_ub: j = %d; column number out of range\n", + j); + switch (lp->col[j]->type) + { case GLP_FR: + case GLP_LO: + ub = +DBL_MAX; break; + case GLP_UP: + case GLP_DB: + case GLP_FX: + ub = lp->col[j]->ub; break; + default: + xassert(lp != lp); + } + return ub; +} + +/*********************************************************************** +* NAME +* +* glp_get_obj_coef - retrieve obj. coefficient or constant term +* +* SYNOPSIS +* +* double glp_get_obj_coef(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_obj_coef returns the objective coefficient at +* j-th structural variable (column) of the specified problem object. +* +* If the parameter j is zero, the routine returns the constant term +* ("shift") of the objective function. */ + +double glp_get_obj_coef(glp_prob *lp, int j) +{ if (!(0 <= j && j <= lp->n)) + xerror("glp_get_obj_coef: j = %d; column number out of range\n" + , j); + return j == 0 ? lp->c0 : lp->col[j]->coef; +} + +/*********************************************************************** +* NAME +* +* glp_get_num_nz - retrieve number of constraint coefficients +* +* SYNOPSIS +* +* int glp_get_num_nz(glp_prob *lp); +* +* RETURNS +* +* The routine glp_get_num_nz returns the number of (non-zero) elements +* in the constraint matrix of the specified problem object. */ + +int glp_get_num_nz(glp_prob *lp) +{ int nnz = lp->nnz; + return nnz; +} + +/*********************************************************************** +* NAME +* +* glp_get_mat_row - retrieve row of the constraint matrix +* +* SYNOPSIS +* +* int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]); +* +* DESCRIPTION +* +* The routine glp_get_mat_row scans (non-zero) elements of i-th row +* of the constraint matrix of the specified problem object and stores +* their column indices and numeric values to locations ind[1], ..., +* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= n +* is the number of elements in i-th row, n is the number of columns. +* +* The parameter ind and/or val can be specified as NULL, in which case +* corresponding information is not stored. +* +* RETURNS +* +* The routine glp_get_mat_row returns the length len, i.e. the number +* of (non-zero) elements in i-th row. */ + +int glp_get_mat_row(glp_prob *lp, int i, int ind[], double val[]) +{ GLPAIJ *aij; + int len; + if (!(1 <= i && i <= lp->m)) + xerror("glp_get_mat_row: i = %d; row number out of range\n", + i); + len = 0; + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) + { len++; + if (ind != NULL) ind[len] = aij->col->j; + if (val != NULL) val[len] = aij->val; + } + xassert(len <= lp->n); + return len; +} + +/*********************************************************************** +* NAME +* +* glp_get_mat_col - retrieve column of the constraint matrix +* +* SYNOPSIS +* +* int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]); +* +* DESCRIPTION +* +* The routine glp_get_mat_col scans (non-zero) elements of j-th column +* of the constraint matrix of the specified problem object and stores +* their row indices and numeric values to locations ind[1], ..., +* ind[len] and val[1], ..., val[len], respectively, where 0 <= len <= m +* is the number of elements in j-th column, m is the number of rows. +* +* The parameter ind or/and val can be specified as NULL, in which case +* corresponding information is not stored. +* +* RETURNS +* +* The routine glp_get_mat_col returns the length len, i.e. the number +* of (non-zero) elements in j-th column. */ + +int glp_get_mat_col(glp_prob *lp, int j, int ind[], double val[]) +{ GLPAIJ *aij; + int len; + if (!(1 <= j && j <= lp->n)) + xerror("glp_get_mat_col: j = %d; column number out of range\n", + j); + len = 0; + for (aij = lp->col[j]->ptr; aij != NULL; aij = aij->c_next) + { len++; + if (ind != NULL) ind[len] = aij->row->i; + if (val != NULL) val[len] = aij->val; + } + xassert(len <= lp->m); + return len; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob3.c b/glpk-5.0/src/api/prob3.c new file mode 100644 index 0000000..16fc852 --- /dev/null +++ b/glpk-5.0/src/api/prob3.c @@ -0,0 +1,164 @@ +/* prob3.c (problem row/column searching routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2013 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_create_index - create the name index +* +* SYNOPSIS +* +* void glp_create_index(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_create_index creates the name index for the +* specified problem object. The name index is an auxiliary data +* structure, which is intended to quickly (i.e. for logarithmic time) +* find rows and columns by their names. +* +* This routine can be called at any time. If the name index already +* exists, the routine does nothing. */ + +void glp_create_index(glp_prob *lp) +{ GLPROW *row; + GLPCOL *col; + int i, j; + /* create row name index */ + if (lp->r_tree == NULL) + { lp->r_tree = avl_create_tree(avl_strcmp, NULL); + for (i = 1; i <= lp->m; i++) + { row = lp->row[i]; + xassert(row->node == NULL); + if (row->name != NULL) + { row->node = avl_insert_node(lp->r_tree, row->name); + avl_set_node_link(row->node, row); + } + } + } + /* create column name index */ + if (lp->c_tree == NULL) + { lp->c_tree = avl_create_tree(avl_strcmp, NULL); + for (j = 1; j <= lp->n; j++) + { col = lp->col[j]; + xassert(col->node == NULL); + if (col->name != NULL) + { col->node = avl_insert_node(lp->c_tree, col->name); + avl_set_node_link(col->node, col); + } + } + } + return; +} + +/*********************************************************************** +* NAME +* +* glp_find_row - find row by its name +* +* SYNOPSIS +* +* int glp_find_row(glp_prob *lp, const char *name); +* +* RETURNS +* +* The routine glp_find_row returns the ordinal number of a row, +* which is assigned (by the routine glp_set_row_name) the specified +* symbolic name. If no such row exists, the routine returns 0. */ + +int glp_find_row(glp_prob *lp, const char *name) +{ AVLNODE *node; + int i = 0; + if (lp->r_tree == NULL) + xerror("glp_find_row: row name index does not exist\n"); + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) + { node = avl_find_node(lp->r_tree, name); + if (node != NULL) + i = ((GLPROW *)avl_get_node_link(node))->i; + } + return i; +} + +/*********************************************************************** +* NAME +* +* glp_find_col - find column by its name +* +* SYNOPSIS +* +* int glp_find_col(glp_prob *lp, const char *name); +* +* RETURNS +* +* The routine glp_find_col returns the ordinal number of a column, +* which is assigned (by the routine glp_set_col_name) the specified +* symbolic name. If no such column exists, the routine returns 0. */ + +int glp_find_col(glp_prob *lp, const char *name) +{ AVLNODE *node; + int j = 0; + if (lp->c_tree == NULL) + xerror("glp_find_col: column name index does not exist\n"); + if (!(name == NULL || name[0] == '\0' || strlen(name) > 255)) + { node = avl_find_node(lp->c_tree, name); + if (node != NULL) + j = ((GLPCOL *)avl_get_node_link(node))->j; + } + return j; +} + +/*********************************************************************** +* NAME +* +* glp_delete_index - delete the name index +* +* SYNOPSIS +* +* void glp_delete_index(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_delete_index deletes the name index previously +* created by the routine glp_create_index and frees the memory +* allocated to this auxiliary data structure. +* +* This routine can be called at any time. If the name index does not +* exist, the routine does nothing. */ + +void glp_delete_index(glp_prob *lp) +{ int i, j; + /* delete row name index */ + if (lp->r_tree != NULL) + { for (i = 1; i <= lp->m; i++) lp->row[i]->node = NULL; + avl_delete_tree(lp->r_tree), lp->r_tree = NULL; + } + /* delete column name index */ + if (lp->c_tree != NULL) + { for (j = 1; j <= lp->n; j++) lp->col[j]->node = NULL; + avl_delete_tree(lp->c_tree), lp->c_tree = NULL; + } + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob4.c b/glpk-5.0/src/api/prob4.c new file mode 100644 index 0000000..6a45161 --- /dev/null +++ b/glpk-5.0/src/api/prob4.c @@ -0,0 +1,154 @@ +/* prob4.c (problem scaling routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2013 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_set_rii - set (change) row scale factor +* +* SYNOPSIS +* +* void glp_set_rii(glp_prob *lp, int i, double rii); +* +* DESCRIPTION +* +* The routine glp_set_rii sets (changes) the scale factor r[i,i] for +* i-th row of the specified problem object. */ + +void glp_set_rii(glp_prob *lp, int i, double rii) +{ if (!(1 <= i && i <= lp->m)) + xerror("glp_set_rii: i = %d; row number out of range\n", i); + if (rii <= 0.0) + xerror("glp_set_rii: i = %d; rii = %g; invalid scale factor\n", + i, rii); + if (lp->valid && lp->row[i]->rii != rii) + { GLPAIJ *aij; + for (aij = lp->row[i]->ptr; aij != NULL; aij = aij->r_next) + { if (aij->col->stat == GLP_BS) + { /* invalidate the basis factorization */ + lp->valid = 0; + break; + } + } + } + lp->row[i]->rii = rii; + return; +} + +/*********************************************************************** +* NAME +* +* glp_set sjj - set (change) column scale factor +* +* SYNOPSIS +* +* void glp_set_sjj(glp_prob *lp, int j, double sjj); +* +* DESCRIPTION +* +* The routine glp_set_sjj sets (changes) the scale factor s[j,j] for +* j-th column of the specified problem object. */ + +void glp_set_sjj(glp_prob *lp, int j, double sjj) +{ if (!(1 <= j && j <= lp->n)) + xerror("glp_set_sjj: j = %d; column number out of range\n", j); + if (sjj <= 0.0) + xerror("glp_set_sjj: j = %d; sjj = %g; invalid scale factor\n", + j, sjj); + if (lp->valid && lp->col[j]->sjj != sjj && lp->col[j]->stat == + GLP_BS) + { /* invalidate the basis factorization */ + lp->valid = 0; + } + lp->col[j]->sjj = sjj; + return; +} + +/*********************************************************************** +* NAME +* +* glp_get_rii - retrieve row scale factor +* +* SYNOPSIS +* +* double glp_get_rii(glp_prob *lp, int i); +* +* RETURNS +* +* The routine glp_get_rii returns current scale factor r[i,i] for i-th +* row of the specified problem object. */ + +double glp_get_rii(glp_prob *lp, int i) +{ if (!(1 <= i && i <= lp->m)) + xerror("glp_get_rii: i = %d; row number out of range\n", i); + return lp->row[i]->rii; +} + +/*********************************************************************** +* NAME +* +* glp_get_sjj - retrieve column scale factor +* +* SYNOPSIS +* +* double glp_get_sjj(glp_prob *lp, int j); +* +* RETURNS +* +* The routine glp_get_sjj returns current scale factor s[j,j] for j-th +* column of the specified problem object. */ + +double glp_get_sjj(glp_prob *lp, int j) +{ if (!(1 <= j && j <= lp->n)) + xerror("glp_get_sjj: j = %d; column number out of range\n", j); + return lp->col[j]->sjj; +} + +/*********************************************************************** +* NAME +* +* glp_unscale_prob - unscale problem data +* +* SYNOPSIS +* +* void glp_unscale_prob(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_unscale_prob performs unscaling of problem data for +* the specified problem object. +* +* "Unscaling" means replacing the current scaling matrices R and S by +* unity matrices that cancels the scaling effect. */ + +void glp_unscale_prob(glp_prob *lp) +{ int m = glp_get_num_rows(lp); + int n = glp_get_num_cols(lp); + int i, j; + for (i = 1; i <= m; i++) glp_set_rii(lp, i, 1.0); + for (j = 1; j <= n; j++) glp_set_sjj(lp, j, 1.0); + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prob5.c b/glpk-5.0/src/api/prob5.c new file mode 100644 index 0000000..c15d048 --- /dev/null +++ b/glpk-5.0/src/api/prob5.c @@ -0,0 +1,166 @@ +/* prob5.c (LP problem basis constructing routines) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2000-2013 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_set_row_stat - set (change) row status +* +* SYNOPSIS +* +* void glp_set_row_stat(glp_prob *lp, int i, int stat); +* +* DESCRIPTION +* +* The routine glp_set_row_stat sets (changes) status of the auxiliary +* variable associated with i-th row. +* +* The new status of the auxiliary variable should be specified by the +* parameter stat as follows: +* +* GLP_BS - basic variable; +* GLP_NL - non-basic variable; +* GLP_NU - non-basic variable on its upper bound; if the variable is +* not double-bounded, this means the same as GLP_NL (only in +* case of this routine); +* GLP_NF - the same as GLP_NL (only in case of this routine); +* GLP_NS - the same as GLP_NL (only in case of this routine). */ + +void glp_set_row_stat(glp_prob *lp, int i, int stat) +{ GLPROW *row; + if (!(1 <= i && i <= lp->m)) + xerror("glp_set_row_stat: i = %d; row number out of range\n", + i); + if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || + stat == GLP_NF || stat == GLP_NS)) + xerror("glp_set_row_stat: i = %d; stat = %d; invalid status\n", + i, stat); + row = lp->row[i]; + if (stat != GLP_BS) + { switch (row->type) + { case GLP_FR: stat = GLP_NF; break; + case GLP_LO: stat = GLP_NL; break; + case GLP_UP: stat = GLP_NU; break; + case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; + case GLP_FX: stat = GLP_NS; break; + default: xassert(row != row); + } + } + if (row->stat == GLP_BS && stat != GLP_BS || + row->stat != GLP_BS && stat == GLP_BS) + { /* invalidate the basis factorization */ + lp->valid = 0; + } + row->stat = stat; + return; +} + +/*********************************************************************** +* NAME +* +* glp_set_col_stat - set (change) column status +* +* SYNOPSIS +* +* void glp_set_col_stat(glp_prob *lp, int j, int stat); +* +* DESCRIPTION +* +* The routine glp_set_col_stat sets (changes) status of the structural +* variable associated with j-th column. +* +* The new status of the structural variable should be specified by the +* parameter stat as follows: +* +* GLP_BS - basic variable; +* GLP_NL - non-basic variable; +* GLP_NU - non-basic variable on its upper bound; if the variable is +* not double-bounded, this means the same as GLP_NL (only in +* case of this routine); +* GLP_NF - the same as GLP_NL (only in case of this routine); +* GLP_NS - the same as GLP_NL (only in case of this routine). */ + +void glp_set_col_stat(glp_prob *lp, int j, int stat) +{ GLPCOL *col; + if (!(1 <= j && j <= lp->n)) + xerror("glp_set_col_stat: j = %d; column number out of range\n" + , j); + if (!(stat == GLP_BS || stat == GLP_NL || stat == GLP_NU || + stat == GLP_NF || stat == GLP_NS)) + xerror("glp_set_col_stat: j = %d; stat = %d; invalid status\n", + j, stat); + col = lp->col[j]; + if (stat != GLP_BS) + { switch (col->type) + { case GLP_FR: stat = GLP_NF; break; + case GLP_LO: stat = GLP_NL; break; + case GLP_UP: stat = GLP_NU; break; + case GLP_DB: if (stat != GLP_NU) stat = GLP_NL; break; + case GLP_FX: stat = GLP_NS; break; + default: xassert(col != col); + } + } + if (col->stat == GLP_BS && stat != GLP_BS || + col->stat != GLP_BS && stat == GLP_BS) + { /* invalidate the basis factorization */ + lp->valid = 0; + } + col->stat = stat; + return; +} + +/*********************************************************************** +* NAME +* +* glp_std_basis - construct standard initial LP basis +* +* SYNOPSIS +* +* void glp_std_basis(glp_prob *lp); +* +* DESCRIPTION +* +* The routine glp_std_basis builds the "standard" (trivial) initial +* basis for the specified problem object. +* +* In the "standard" basis all auxiliary variables are basic, and all +* structural variables are non-basic. */ + +void glp_std_basis(glp_prob *lp) +{ int i, j; + /* make all auxiliary variables basic */ + for (i = 1; i <= lp->m; i++) + glp_set_row_stat(lp, i, GLP_BS); + /* make all structural variables non-basic */ + for (j = 1; j <= lp->n; j++) + { GLPCOL *col = lp->col[j]; + if (col->type == GLP_DB && fabs(col->lb) > fabs(col->ub)) + glp_set_col_stat(lp, j, GLP_NU); + else + glp_set_col_stat(lp, j, GLP_NL); + } + return; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prrngs.c b/glpk-5.0/src/api/prrngs.c new file mode 100644 index 0000000..962614a --- /dev/null +++ b/glpk-5.0/src/api/prrngs.c @@ -0,0 +1,300 @@ +/* prrngs.c (print sensitivity analysis report) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +static char *format(char buf[13+1], double x) +{ /* format floating-point number in MPS/360-like style */ + if (x == -DBL_MAX) + strcpy(buf, " -Inf"); + else if (x == +DBL_MAX) + strcpy(buf, " +Inf"); + else if (fabs(x) <= 999999.99998) + { sprintf(buf, "%13.5f", x); +#if 1 + if (strcmp(buf, " 0.00000") == 0 || + strcmp(buf, " -0.00000") == 0) + strcpy(buf, " . "); + else if (memcmp(buf, " 0.", 8) == 0) + memcpy(buf, " .", 8); + else if (memcmp(buf, " -0.", 8) == 0) + memcpy(buf, " -.", 8); +#endif + } + else + sprintf(buf, "%13.6g", x); + return buf; +} + +int glp_print_ranges(glp_prob *P, int len, const int list[], + int flags, const char *fname) +{ /* print sensitivity analysis report */ + glp_file *fp = NULL; + GLPROW *row; + GLPCOL *col; + int m, n, pass, k, t, numb, type, stat, var1, var2, count, page, + ret; + double lb, ub, slack, coef, prim, dual, value1, value2, coef1, + coef2, obj1, obj2; + const char *name, *limit; + char buf[13+1]; + /* sanity checks */ +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_print_ranges: P = %p; invalid problem object\n", + P); +#endif + m = P->m, n = P->n; + if (len < 0) + xerror("glp_print_ranges: len = %d; invalid list length\n", + len); + if (len > 0) + { if (list == NULL) + xerror("glp_print_ranges: list = %p: invalid parameter\n", + list); + for (t = 1; t <= len; t++) + { k = list[t]; + if (!(1 <= k && k <= m+n)) + xerror("glp_print_ranges: list[%d] = %d; row/column numb" + "er out of range\n", t, k); + } + } + if (flags != 0) + xerror("glp_print_ranges: flags = %d; invalid parameter\n", + flags); + if (fname == NULL) + xerror("glp_print_ranges: fname = %p; invalid parameter\n", + fname); + if (glp_get_status(P) != GLP_OPT) + { xprintf("glp_print_ranges: optimal basic solution required\n"); + ret = 1; + goto done; + } + if (!glp_bf_exists(P)) + { xprintf("glp_print_ranges: basis factorization required\n"); + ret = 2; + goto done; + } + /* start reporting */ + xprintf("Write sensitivity analysis report to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 3; + goto done; + } + page = count = 0; + for (pass = 1; pass <= 2; pass++) + for (t = 1; t <= (len == 0 ? m+n : len); t++) + { if (t == 1) count = 0; + k = (len == 0 ? t : list[t]); + if (pass == 1 && k > m || pass == 2 && k <= m) + continue; + if (count == 0) + { xfprintf(fp, "GLPK %-4s - SENSITIVITY ANALYSIS REPORT%73sPa" + "ge%4d\n", glp_version(), "", ++page); + xfprintf(fp, "\n"); + xfprintf(fp, "%-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name); + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->obj_val, + P->dir == GLP_MIN ? "MINimum" : + P->dir == GLP_MAX ? "MAXimum" : "???"); + xfprintf(fp, "\n"); + xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s " + "%s\n", "No.", pass == 1 ? "Row name" : "Column name", + "St", "Activity", pass == 1 ? "Slack" : "Obj coef", + "Lower bound", "Activity", "Obj coef", "Obj value at", + "Limiting"); + xfprintf(fp, "%6s %-12s %2s %13s %13s %13s %13s %13s %13s " + "%s\n", "", "", "", "", "Marginal", "Upper bound", + "range", "range", "break point", "variable"); + xfprintf(fp, "------ ------------ -- ------------- --------" + "----- ------------- ------------- ------------- ------" + "------- ------------\n"); + } + if (pass == 1) + { numb = k; + xassert(1 <= numb && numb <= m); + row = P->row[numb]; + name = row->name; + type = row->type; + lb = glp_get_row_lb(P, numb); + ub = glp_get_row_ub(P, numb); + coef = 0.0; + stat = row->stat; + prim = row->prim; + if (type == GLP_FR) + slack = - prim; + else if (type == GLP_LO) + slack = lb - prim; + else if (type == GLP_UP || type == GLP_DB || type == GLP_FX) + slack = ub - prim; + dual = row->dual; + } + else + { numb = k - m; + xassert(1 <= numb && numb <= n); + col = P->col[numb]; + name = col->name; + lb = glp_get_col_lb(P, numb); + ub = glp_get_col_ub(P, numb); + coef = col->coef; + stat = col->stat; + prim = col->prim; + slack = 0.0; + dual = col->dual; + } + if (stat != GLP_BS) + { glp_analyze_bound(P, k, &value1, &var1, &value2, &var2); + if (stat == GLP_NF) + coef1 = coef2 = coef; + else if (stat == GLP_NS) + coef1 = -DBL_MAX, coef2 = +DBL_MAX; + else if (stat == GLP_NL && P->dir == GLP_MIN || + stat == GLP_NU && P->dir == GLP_MAX) + coef1 = coef - dual, coef2 = +DBL_MAX; + else + coef1 = -DBL_MAX, coef2 = coef - dual; + if (value1 == -DBL_MAX) + { if (dual < -1e-9) + obj1 = +DBL_MAX; + else if (dual > +1e-9) + obj1 = -DBL_MAX; + else + obj1 = P->obj_val; + } + else + obj1 = P->obj_val + dual * (value1 - prim); + if (value2 == +DBL_MAX) + { if (dual < -1e-9) + obj2 = -DBL_MAX; + else if (dual > +1e-9) + obj2 = +DBL_MAX; + else + obj2 = P->obj_val; + } + else + obj2 = P->obj_val + dual * (value2 - prim); + } + else + { glp_analyze_coef(P, k, &coef1, &var1, &value1, &coef2, + &var2, &value2); + if (coef1 == -DBL_MAX) + { if (prim < -1e-9) + obj1 = +DBL_MAX; + else if (prim > +1e-9) + obj1 = -DBL_MAX; + else + obj1 = P->obj_val; + } + else + obj1 = P->obj_val + (coef1 - coef) * prim; + if (coef2 == +DBL_MAX) + { if (prim < -1e-9) + obj2 = -DBL_MAX; + else if (prim > +1e-9) + obj2 = +DBL_MAX; + else + obj2 = P->obj_val; + } + else + obj2 = P->obj_val + (coef2 - coef) * prim; + } + /*** first line ***/ + /* row/column number */ + xfprintf(fp, "%6d", numb); + /* row/column name */ + xfprintf(fp, " %-12.12s", name == NULL ? "" : name); + if (name != NULL && strlen(name) > 12) + xfprintf(fp, "%s\n%6s %12s", name+12, "", ""); + /* row/column status */ + xfprintf(fp, " %2s", + stat == GLP_BS ? "BS" : stat == GLP_NL ? "NL" : + stat == GLP_NU ? "NU" : stat == GLP_NF ? "NF" : + stat == GLP_NS ? "NS" : "??"); + /* row/column activity */ + xfprintf(fp, " %s", format(buf, prim)); + /* row slack, column objective coefficient */ + xfprintf(fp, " %s", format(buf, k <= m ? slack : coef)); + /* row/column lower bound */ + xfprintf(fp, " %s", format(buf, lb)); + /* row/column activity range */ + xfprintf(fp, " %s", format(buf, value1)); + /* row/column objective coefficient range */ + xfprintf(fp, " %s", format(buf, coef1)); + /* objective value at break point */ + xfprintf(fp, " %s", format(buf, obj1)); + /* limiting variable name */ + if (var1 != 0) + { if (var1 <= m) + limit = glp_get_row_name(P, var1); + else + limit = glp_get_col_name(P, var1 - m); + if (limit != NULL) + xfprintf(fp, " %s", limit); + } + xfprintf(fp, "\n"); + /*** second line ***/ + xfprintf(fp, "%6s %-12s %2s %13s", "", "", "", ""); + /* row/column reduced cost */ + xfprintf(fp, " %s", format(buf, dual)); + /* row/column upper bound */ + xfprintf(fp, " %s", format(buf, ub)); + /* row/column activity range */ + xfprintf(fp, " %s", format(buf, value2)); + /* row/column objective coefficient range */ + xfprintf(fp, " %s", format(buf, coef2)); + /* objective value at break point */ + xfprintf(fp, " %s", format(buf, obj2)); + /* limiting variable name */ + if (var2 != 0) + { if (var2 <= m) + limit = glp_get_row_name(P, var2); + else + limit = glp_get_col_name(P, var2 - m); + if (limit != NULL) + xfprintf(fp, " %s", limit); + } + xfprintf(fp, "\n"); + xfprintf(fp, "\n"); + /* print 10 items per page */ + count = (count + 1) % 10; + } + xfprintf(fp, "End of report\n"); +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 4; + goto done; + } + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/prsol.c b/glpk-5.0/src/api/prsol.c new file mode 100644 index 0000000..4ba6730 --- /dev/null +++ b/glpk-5.0/src/api/prsol.c @@ -0,0 +1,200 @@ +/* prsol.c (write basic solution in printable format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_print_sol(glp_prob *P, const char *fname) +{ /* write basic solution in printable format */ + glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, t, ae_ind, re_ind, ret; + double ae_max, re_max; + xprintf("Writing basic solution to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "%-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name); + xfprintf(fp, "%-12s%d\n", "Rows:", P->m); + xfprintf(fp, "%-12s%d\n", "Columns:", P->n); + xfprintf(fp, "%-12s%d\n", "Non-zeros:", P->nnz); + t = glp_get_status(P); + xfprintf(fp, "%-12s%s\n", "Status:", + t == GLP_OPT ? "OPTIMAL" : + t == GLP_FEAS ? "FEASIBLE" : + t == GLP_INFEAS ? "INFEASIBLE (INTERMEDIATE)" : + t == GLP_NOFEAS ? "INFEASIBLE (FINAL)" : + t == GLP_UNBND ? "UNBOUNDED" : + t == GLP_UNDEF ? "UNDEFINED" : "???"); + xfprintf(fp, "%-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->obj_val, + P->dir == GLP_MIN ? "MINimum" : + P->dir == GLP_MAX ? "MAXimum" : "???"); + xfprintf(fp, "\n"); + xfprintf(fp, " No. Row name St Activity Lower bound " + " Upper bound Marginal\n"); + xfprintf(fp, "------ ------------ -- ------------- ------------- " + "------------- -------------\n"); + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + xfprintf(fp, "%6d ", i); + if (row->name == NULL || strlen(row->name) <= 12) + xfprintf(fp, "%-12s ", row->name == NULL ? "" : row->name); + else + xfprintf(fp, "%s\n%20s", row->name, ""); + xfprintf(fp, "%s ", + row->stat == GLP_BS ? "B " : + row->stat == GLP_NL ? "NL" : + row->stat == GLP_NU ? "NU" : + row->stat == GLP_NF ? "NF" : + row->stat == GLP_NS ? "NS" : "??"); + xfprintf(fp, "%13.6g ", + fabs(row->prim) <= 1e-9 ? 0.0 : row->prim); + if (row->type == GLP_LO || row->type == GLP_DB || + row->type == GLP_FX) + xfprintf(fp, "%13.6g ", row->lb); + else + xfprintf(fp, "%13s ", ""); + if (row->type == GLP_UP || row->type == GLP_DB) + xfprintf(fp, "%13.6g ", row->ub); + else + xfprintf(fp, "%13s ", row->type == GLP_FX ? "=" : ""); + if (row->stat != GLP_BS) + { if (fabs(row->dual) <= 1e-9) + xfprintf(fp, "%13s", "< eps"); + else + xfprintf(fp, "%13.6g ", row->dual); + } + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, " No. Column name St Activity Lower bound " + " Upper bound Marginal\n"); + xfprintf(fp, "------ ------------ -- ------------- ------------- " + "------------- -------------\n"); + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + xfprintf(fp, "%6d ", j); + if (col->name == NULL || strlen(col->name) <= 12) + xfprintf(fp, "%-12s ", col->name == NULL ? "" : col->name); + else + xfprintf(fp, "%s\n%20s", col->name, ""); + xfprintf(fp, "%s ", + col->stat == GLP_BS ? "B " : + col->stat == GLP_NL ? "NL" : + col->stat == GLP_NU ? "NU" : + col->stat == GLP_NF ? "NF" : + col->stat == GLP_NS ? "NS" : "??"); + xfprintf(fp, "%13.6g ", + fabs(col->prim) <= 1e-9 ? 0.0 : col->prim); + if (col->type == GLP_LO || col->type == GLP_DB || + col->type == GLP_FX) + xfprintf(fp, "%13.6g ", col->lb); + else + xfprintf(fp, "%13s ", ""); + if (col->type == GLP_UP || col->type == GLP_DB) + xfprintf(fp, "%13.6g ", col->ub); + else + xfprintf(fp, "%13s ", col->type == GLP_FX ? "=" : ""); + if (col->stat != GLP_BS) + { if (fabs(col->dual) <= 1e-9) + xfprintf(fp, "%13s", "< eps"); + else + xfprintf(fp, "%13.6g ", col->dual); + } + xfprintf(fp, "\n"); + } + xfprintf(fp, "\n"); + xfprintf(fp, "Karush-Kuhn-Tucker optimality conditions:\n"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_SOL, GLP_KKT_PE, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PE: max.abs.err = %.2e on row %d\n", + ae_max, ae_ind); + xfprintf(fp, " max.rel.err = %.2e on row %d\n", + re_max, re_ind); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS WRONG"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_SOL, GLP_KKT_PB, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.PB: max.abs.err = %.2e on %s %d\n", + ae_max, ae_ind <= P->m ? "row" : "column", + ae_ind <= P->m ? ae_ind : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on %s %d\n", + re_max, re_ind <= P->m ? "row" : "column", + re_ind <= P->m ? re_ind : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "PRIMAL SOLUTION IS INFEASIBL" + "E"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_SOL, GLP_KKT_DE, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.DE: max.abs.err = %.2e on column %d\n", + ae_max, ae_ind == 0 ? 0 : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on column %d\n", + re_max, re_ind == 0 ? 0 : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS WRONG"); + xfprintf(fp, "\n"); + glp_check_kkt(P, GLP_SOL, GLP_KKT_DB, &ae_max, &ae_ind, &re_max, + &re_ind); + xfprintf(fp, "KKT.DB: max.abs.err = %.2e on %s %d\n", + ae_max, ae_ind <= P->m ? "row" : "column", + ae_ind <= P->m ? ae_ind : ae_ind - P->m); + xfprintf(fp, " max.rel.err = %.2e on %s %d\n", + re_max, re_ind <= P->m ? "row" : "column", + re_ind <= P->m ? re_ind : re_ind - P->m); + xfprintf(fp, "%8s%s\n", "", + re_max <= 1e-9 ? "High quality" : + re_max <= 1e-6 ? "Medium quality" : + re_max <= 1e-3 ? "Low quality" : "DUAL SOLUTION IS INFEASIBLE") + ; + xfprintf(fp, "\n"); + xfprintf(fp, "End of output\n"); +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdasn.c b/glpk-5.0/src/api/rdasn.c new file mode 100644 index 0000000..1f22003 --- /dev/null +++ b/glpk-5.0/src/api/rdasn.c @@ -0,0 +1,162 @@ +/* rdasn.c (read assignment problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +/*********************************************************************** +* NAME +* +* glp_read_asnprob - read assignment problem data in DIMACS format +* +* SYNOPSIS +* +* int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_asnprob reads assignment problem data in DIMACS +* format from a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_asnprob(glp_graph *G, int v_set, int a_cost, const char + *fname) +{ DMX _csa, *csa = &_csa; + glp_vertex *v; + glp_arc *a; + int nv, na, n1, i, j, k, ret = 0; + double cost; + char *flag = NULL; + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_read_asnprob: v_set = %d; invalid offset\n", + v_set); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_read_asnprob: a_cost = %d; invalid offset\n", + a_cost); + glp_erase_graph(G, G->v_size, G->a_size); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading assignment problem data from '%s'...\n", fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "asn") != 0) + error(csa, "wrong problem designator; 'asn' expected"); + read_field(csa); + if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) + error(csa, "number of nodes missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &na) == 0 && na >= 0)) + error(csa, "number of arcs missing or invalid"); + if (nv > 0) glp_add_vertices(G, nv); + end_of_line(csa); + /* read node descriptor lines */ + flag = xcalloc(1+nv, sizeof(char)); + memset(&flag[1], 0, nv * sizeof(char)); + n1 = 0; + for (;;) + { read_designator(csa); + if (strcmp(csa->field, "n") != 0) break; + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "node number %d out of range", i); + if (flag[i]) + error(csa, "duplicate descriptor of node %d", i); + flag[i] = 1, n1++; + end_of_line(csa); + } + xprintf( + "Assignment problem has %d + %d = %d node%s and %d arc%s\n", + n1, nv - n1, nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); + if (v_set >= 0) + { for (i = 1; i <= nv; i++) + { v = G->v[i]; + k = (flag[i] ? 0 : 1); + memcpy((char *)v->data + v_set, &k, sizeof(int)); + } + } + /* read arc descriptor lines */ + for (k = 1; k <= na; k++) + { if (k > 1) read_designator(csa); + if (strcmp(csa->field, "a") != 0) + error(csa, "wrong line designator; 'a' expected"); + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "starting node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "starting node number %d out of range", i); + if (!flag[i]) + error(csa, "node %d cannot be a starting node", i); + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "ending node number missing or invalid"); + if (!(1 <= j && j <= nv)) + error(csa, "ending node number %d out of range", j); + if (flag[j]) + error(csa, "node %d cannot be an ending node", j); + read_field(csa); + if (str2num(csa->field, &cost) != 0) + error(csa, "arc cost missing or invalid"); + check_int(csa, cost); + a = glp_add_arc(G, i, j); + if (a_cost >= 0) + memcpy((char *)a->data + a_cost, &cost, sizeof(double)); + end_of_line(csa); + } + xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); + if (csa->fp != NULL) glp_close(csa->fp); + if (flag != NULL) xfree(flag); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdcc.c b/glpk-5.0/src/api/rdcc.c new file mode 100644 index 0000000..1e93a77 --- /dev/null +++ b/glpk-5.0/src/api/rdcc.c @@ -0,0 +1,160 @@ +/* rdcc.c (read graph in DIMACS clique/coloring format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +/*********************************************************************** +* NAME +* +* glp_read_ccdata - read graph in DIMACS clique/coloring format +* +* SYNOPSIS +* +* int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_ccdata reads an (undirected) graph in DIMACS +* clique/coloring format from a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_ccdata(glp_graph *G, int v_wgt, const char *fname) +{ DMX _csa, *csa = &_csa; + glp_vertex *v; + int i, j, k, nv, ne, ret = 0; + double w; + char *flag = NULL; + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) + xerror("glp_read_ccdata: v_wgt = %d; invalid offset\n", + v_wgt); + glp_erase_graph(G, G->v_size, G->a_size); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading graph from '%s'...\n", fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "edge") != 0) + error(csa, "wrong problem designator; 'edge' expected"); + read_field(csa); + if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) + error(csa, "number of vertices missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &ne) == 0 && ne >= 0)) + error(csa, "number of edges missing or invalid"); + xprintf("Graph has %d vert%s and %d edge%s\n", + nv, nv == 1 ? "ex" : "ices", ne, ne == 1 ? "" : "s"); + if (nv > 0) glp_add_vertices(G, nv); + end_of_line(csa); + /* read node descriptor lines */ + flag = xcalloc(1+nv, sizeof(char)); + memset(&flag[1], 0, nv * sizeof(char)); + if (v_wgt >= 0) + { w = 1.0; + for (i = 1; i <= nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_wgt, &w, sizeof(double)); + } + } + for (;;) + { read_designator(csa); + if (strcmp(csa->field, "n") != 0) break; + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "vertex number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "vertex number %d out of range", i); + if (flag[i]) + error(csa, "duplicate descriptor of vertex %d", i); + read_field(csa); + if (str2num(csa->field, &w) != 0) + error(csa, "vertex weight missing or invalid"); + check_int(csa, w); + if (v_wgt >= 0) + { v = G->v[i]; + memcpy((char *)v->data + v_wgt, &w, sizeof(double)); + } + flag[i] = 1; + end_of_line(csa); + } + xfree(flag), flag = NULL; + /* read edge descriptor lines */ + for (k = 1; k <= ne; k++) + { if (k > 1) read_designator(csa); + if (strcmp(csa->field, "e") != 0) + error(csa, "wrong line designator; 'e' expected"); + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "first vertex number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "first vertex number %d out of range", i); + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "second vertex number missing or invalid"); + if (!(1 <= j && j <= nv)) + error(csa, "second vertex number %d out of range", j); + glp_add_arc(G, i, j); + end_of_line(csa); + } + xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); + if (csa->fp != NULL) glp_close(csa->fp); + if (flag != NULL) xfree(flag); + return ret; +} + +/**********************************************************************/ + +int glp_read_graph(glp_graph *G, const char *fname) +{ return + glp_read_ccdata(G, -1, fname); +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdcnf.c b/glpk-5.0/src/api/rdcnf.c new file mode 100644 index 0000000..f879a3c --- /dev/null +++ b/glpk-5.0/src/api/rdcnf.c @@ -0,0 +1,134 @@ +/* rdcnf.c (read CNF-SAT problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +int glp_read_cnfsat(glp_prob *P, const char *fname) +{ /* read CNF-SAT problem data in DIMACS format */ + DMX _csa, *csa = &_csa; + int m, n, i, j, len, neg, rhs, ret = 0, *ind = NULL; + double *val = NULL; + char *map = NULL; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_read_cnfsat: P = %p; invalid problem object\n", + P); +#endif + if (fname == NULL) + xerror("glp_read_cnfsat: fname = %p; invalid parameter\n", + fname); + glp_erase_prob(P); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading CNF-SAT problem data from '%s'...\n", fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "cnf") != 0) + error(csa, "wrong problem designator; 'cnf' expected\n"); + read_field(csa); + if (!(str2int(csa->field, &n) == 0 && n >= 0)) + error(csa, "number of variables missing or invalid\n"); + read_field(csa); + if (!(str2int(csa->field, &m) == 0 && m >= 0)) + error(csa, "number of clauses missing or invalid\n"); + xprintf("Instance has %d variable%s and %d clause%s\n", + n, n == 1 ? "" : "s", m, m == 1 ? "" : "s"); + end_of_line(csa); + if (m > 0) + glp_add_rows(P, m); + if (n > 0) + { glp_add_cols(P, n); + for (j = 1; j <= n; j++) + glp_set_col_kind(P, j, GLP_BV); + } + /* allocate working arrays */ + ind = xcalloc(1+n, sizeof(int)); + val = xcalloc(1+n, sizeof(double)); + map = xcalloc(1+n, sizeof(char)); + for (j = 1; j <= n; j++) map[j] = 0; + /* read clauses */ + for (i = 1; i <= m; i++) + { /* read i-th clause */ + len = 0, rhs = 1; + for (;;) + { /* skip white-space characters */ + while (csa->c == ' ' || csa->c == '\n') + read_char(csa); + /* read term */ + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "variable number missing or invalid\n"); + if (j > 0) + neg = 0; + else if (j < 0) + neg = 1, j = -j, rhs--; + else + break; + if (!(1 <= j && j <= n)) + error(csa, "variable number out of range\n"); + if (map[j]) + error(csa, "duplicate variable number\n"); + len++, ind[len] = j, val[len] = (neg ? -1.0 : +1.0); + map[j] = 1; + } + glp_set_row_bnds(P, i, GLP_LO, (double)rhs, 0.0); + glp_set_mat_row(P, i, len, ind, val); + while (len > 0) map[ind[len--]] = 0; + } + xprintf("%d lines were read\n", csa->count); + /* problem data has been successfully read */ + glp_sort_matrix(P); +done: if (csa->fp != NULL) glp_close(csa->fp); + if (ind != NULL) xfree(ind); + if (val != NULL) xfree(val); + if (map != NULL) xfree(map); + if (ret) glp_erase_prob(P); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdipt.c b/glpk-5.0/src/api/rdipt.c new file mode 100644 index 0000000..62bad69 --- /dev/null +++ b/glpk-5.0/src/api/rdipt.c @@ -0,0 +1,183 @@ +/* rdipt.c (read interior-point solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_read_ipt - read interior-point solution in GLPK format +* +* SYNOPSIS +* +* int glp_read_ipt(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_ipt reads interior-point solution from a text +* file in GLPK format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_ipt(glp_prob *P, const char *fname) +{ DMX dmx_, *dmx = &dmx_; + int i, j, k, m, n, sst, ret = 1; + char *stat = NULL; + double obj, *prim = NULL, *dual = NULL; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_read_ipt: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_read_ipt: fname = %d; invalid parameter\n", fname); + if (setjmp(dmx->jump)) + goto done; + dmx->fname = fname; + dmx->fp = NULL; + dmx->count = 0; + dmx->c = '\n'; + dmx->field[0] = '\0'; + dmx->empty = dmx->nonint = 0; + xprintf("Reading interior-point solution from '%s'...\n", fname); + dmx->fp = glp_open(fname, "r"); + if (dmx->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* read solution line */ + dmx_read_designator(dmx); + if (strcmp(dmx->field, "s") != 0) + dmx_error(dmx, "solution line missing or invalid"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "ipt") != 0) + dmx_error(dmx, "wrong solution designator; 'ipt' expected"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &m) == 0 && m >= 0)) + dmx_error(dmx, "number of rows missing or invalid"); + if (m != P->m) + dmx_error(dmx, "number of rows mismatch"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &n) == 0 && n >= 0)) + dmx_error(dmx, "number of columns missing or invalid"); + if (n != P->n) + dmx_error(dmx, "number of columns mismatch"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "o") == 0) + sst = GLP_OPT; + else if (strcmp(dmx->field, "i") == 0) + sst = GLP_INFEAS; + else if (strcmp(dmx->field, "n") == 0) + sst = GLP_NOFEAS; + else if (strcmp(dmx->field, "u") == 0) + sst = GLP_UNDEF; + else + dmx_error(dmx, "solution status missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &obj) != 0) + dmx_error(dmx, "objective value missing or invalid"); + dmx_end_of_line(dmx); + /* allocate working arrays */ + stat = xalloc(1+m+n, sizeof(stat[0])); + for (k = 1; k <= m+n; k++) + stat[k] = '?'; + prim = xalloc(1+m+n, sizeof(prim[0])); + dual = xalloc(1+m+n, sizeof(dual[0])); + /* read solution descriptor lines */ + for (;;) + { dmx_read_designator(dmx); + if (strcmp(dmx->field, "i") == 0) + { /* row solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &i) != 0) + dmx_error(dmx, "row number missing or invalid"); + if (!(1 <= i && i <= m)) + dmx_error(dmx, "row number out of range"); + if (stat[i] != '?') + dmx_error(dmx, "duplicate row solution descriptor"); + stat[i] = GLP_BS; + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[i]) != 0) + dmx_error(dmx, "row primal value missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &dual[i]) != 0) + dmx_error(dmx, "row dual value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "j") == 0) + { /* column solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &j) != 0) + dmx_error(dmx, "column number missing or invalid"); + if (!(1 <= j && j <= n)) + dmx_error(dmx, "column number out of range"); + if (stat[m+j] != '?') + dmx_error(dmx, "duplicate column solution descriptor"); + stat[m+j] = GLP_BS; + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[m+j]) != 0) + dmx_error(dmx, "column primal value missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &dual[m+j]) != 0) + dmx_error(dmx, "column dual value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "e") == 0) + break; + else + dmx_error(dmx, "line designator missing or invalid"); + dmx_end_of_line(dmx); + } + /* store solution components into problem object */ + for (k = 1; k <= m+n; k++) + { if (stat[k] == '?') + dmx_error(dmx, "incomplete interior-point solution"); + } + P->ipt_stat = sst; + P->ipt_obj = obj; + for (i = 1; i <= m; i++) + { P->row[i]->pval = prim[i]; + P->row[i]->dval = dual[i]; + } + for (j = 1; j <= n; j++) + { P->col[j]->pval = prim[m+j]; + P->col[j]->dval = dual[m+j]; + } + /* interior-point solution has been successfully read */ + xprintf("%d lines were read\n", dmx->count); + ret = 0; +done: if (dmx->fp != NULL) + glp_close(dmx->fp); + if (stat != NULL) + xfree(stat); + if (prim != NULL) + xfree(prim); + if (dual != NULL) + xfree(dual); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmaxf.c b/glpk-5.0/src/api/rdmaxf.c new file mode 100644 index 0000000..e30a07c --- /dev/null +++ b/glpk-5.0/src/api/rdmaxf.c @@ -0,0 +1,161 @@ +/* rdmaxf.c (read maximum flow problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +/*********************************************************************** +* NAME +* +* glp_read_maxflow - read maximum flow problem data in DIMACS format +* +* SYNOPSIS +* +* int glp_read_maxflow(glp_graph *G, int *s, int *t, int a_cap, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_maxflow reads maximum flow problem data in +* DIMACS format from a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_maxflow(glp_graph *G, int *_s, int *_t, int a_cap, + const char *fname) +{ DMX _csa, *csa = &_csa; + glp_arc *a; + int i, j, k, s, t, nv, na, ret = 0; + double cap; + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_read_maxflow: a_cap = %d; invalid offset\n", + a_cap); + glp_erase_graph(G, G->v_size, G->a_size); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading maximum flow problem data from '%s'...\n", + fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "max") != 0) + error(csa, "wrong problem designator; 'max' expected"); + read_field(csa); + if (!(str2int(csa->field, &nv) == 0 && nv >= 2)) + error(csa, "number of nodes missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &na) == 0 && na >= 0)) + error(csa, "number of arcs missing or invalid"); + xprintf("Flow network has %d node%s and %d arc%s\n", + nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); + if (nv > 0) glp_add_vertices(G, nv); + end_of_line(csa); + /* read node descriptor lines */ + s = t = 0; + for (;;) + { read_designator(csa); + if (strcmp(csa->field, "n") != 0) break; + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "node number %d out of range", i); + read_field(csa); + if (strcmp(csa->field, "s") == 0) + { if (s > 0) + error(csa, "only one source node allowed"); + s = i; + } + else if (strcmp(csa->field, "t") == 0) + { if (t > 0) + error(csa, "only one sink node allowed"); + t = i; + } + else + error(csa, "wrong node designator; 's' or 't' expected"); + if (s > 0 && s == t) + error(csa, "source and sink nodes must be distinct"); + end_of_line(csa); + } + if (s == 0) + error(csa, "source node descriptor missing\n"); + if (t == 0) + error(csa, "sink node descriptor missing\n"); + if (_s != NULL) *_s = s; + if (_t != NULL) *_t = t; + /* read arc descriptor lines */ + for (k = 1; k <= na; k++) + { if (k > 1) read_designator(csa); + if (strcmp(csa->field, "a") != 0) + error(csa, "wrong line designator; 'a' expected"); + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "starting node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "starting node number %d out of range", i); + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "ending node number missing or invalid"); + if (!(1 <= j && j <= nv)) + error(csa, "ending node number %d out of range", j); + read_field(csa); + if (!(str2num(csa->field, &cap) == 0 && cap >= 0.0)) + error(csa, "arc capacity missing or invalid"); + check_int(csa, cap); + a = glp_add_arc(G, i, j); + if (a_cap >= 0) + memcpy((char *)a->data + a_cap, &cap, sizeof(double)); + end_of_line(csa); + } + xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); + if (csa->fp != NULL) glp_close(csa->fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmcf.c b/glpk-5.0/src/api/rdmcf.c new file mode 100644 index 0000000..716254d --- /dev/null +++ b/glpk-5.0/src/api/rdmcf.c @@ -0,0 +1,184 @@ +/* rdmcf.c (read min-cost flow problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "glpk.h" +#include "misc.h" + +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +/*********************************************************************** +* NAME +* +* glp_read_mincost - read min-cost flow problem data in DIMACS format +* +* SYNOPSIS +* +* int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +* int a_cost, const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_mincost reads minimum cost flow problem data in +* DIMACS format from a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, + int a_cost, const char *fname) +{ DMX _csa, *csa = &_csa; + glp_vertex *v; + glp_arc *a; + int i, j, k, nv, na, ret = 0; + double rhs, low, cap, cost; + char *flag = NULL; + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) + xerror("glp_read_mincost: v_rhs = %d; invalid offset\n", + v_rhs); + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) + xerror("glp_read_mincost: a_low = %d; invalid offset\n", + a_low); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_read_mincost: a_cap = %d; invalid offset\n", + a_cap); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_read_mincost: a_cost = %d; invalid offset\n", + a_cost); + glp_erase_graph(G, G->v_size, G->a_size); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading min-cost flow problem data from '%s'...\n", + fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "min") != 0) + error(csa, "wrong problem designator; 'min' expected"); + read_field(csa); + if (!(str2int(csa->field, &nv) == 0 && nv >= 0)) + error(csa, "number of nodes missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &na) == 0 && na >= 0)) + error(csa, "number of arcs missing or invalid"); + xprintf("Flow network has %d node%s and %d arc%s\n", + nv, nv == 1 ? "" : "s", na, na == 1 ? "" : "s"); + if (nv > 0) glp_add_vertices(G, nv); + end_of_line(csa); + /* read node descriptor lines */ + flag = xcalloc(1+nv, sizeof(char)); + memset(&flag[1], 0, nv * sizeof(char)); + if (v_rhs >= 0) + { rhs = 0.0; + for (i = 1; i <= nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); + } + } + for (;;) + { read_designator(csa); + if (strcmp(csa->field, "n") != 0) break; + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "node number %d out of range", i); + if (flag[i]) + error(csa, "duplicate descriptor of node %d", i); + read_field(csa); + if (str2num(csa->field, &rhs) != 0) + error(csa, "node supply/demand missing or invalid"); + check_int(csa, rhs); + if (v_rhs >= 0) + { v = G->v[i]; + memcpy((char *)v->data + v_rhs, &rhs, sizeof(double)); + } + flag[i] = 1; + end_of_line(csa); + } + xfree(flag), flag = NULL; + /* read arc descriptor lines */ + for (k = 1; k <= na; k++) + { if (k > 1) read_designator(csa); + if (strcmp(csa->field, "a") != 0) + error(csa, "wrong line designator; 'a' expected"); + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "starting node number missing or invalid"); + if (!(1 <= i && i <= nv)) + error(csa, "starting node number %d out of range", i); + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "ending node number missing or invalid"); + if (!(1 <= j && j <= nv)) + error(csa, "ending node number %d out of range", j); + read_field(csa); + if (!(str2num(csa->field, &low) == 0 && low >= 0.0)) + error(csa, "lower bound of arc flow missing or invalid"); + check_int(csa, low); + read_field(csa); + if (!(str2num(csa->field, &cap) == 0 && cap >= low)) + error(csa, "upper bound of arc flow missing or invalid"); + check_int(csa, cap); + read_field(csa); + if (str2num(csa->field, &cost) != 0) + error(csa, "per-unit cost of arc flow missing or invalid"); + check_int(csa, cost); + a = glp_add_arc(G, i, j); + if (a_low >= 0) + memcpy((char *)a->data + a_low, &low, sizeof(double)); + if (a_cap >= 0) + memcpy((char *)a->data + a_cap, &cap, sizeof(double)); + if (a_cost >= 0) + memcpy((char *)a->data + a_cost, &cost, sizeof(double)); + end_of_line(csa); + } + xprintf("%d lines were read\n", csa->count); +done: if (ret) glp_erase_graph(G, G->v_size, G->a_size); + if (csa->fp != NULL) glp_close(csa->fp); + if (flag != NULL) xfree(flag); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdmip.c b/glpk-5.0/src/api/rdmip.c new file mode 100644 index 0000000..e6f4589 --- /dev/null +++ b/glpk-5.0/src/api/rdmip.c @@ -0,0 +1,170 @@ +/* rdmip.c (read MIP solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_read_mip - read MIP solution in GLPK format +* +* SYNOPSIS +* +* int glp_read_mip(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_mip reads MIP solution from a text file in GLPK +* format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_mip(glp_prob *P, const char *fname) +{ DMX dmx_, *dmx = &dmx_; + int i, j, k, m, n, sst, ret = 1; + char *stat = NULL; + double obj, *prim = NULL; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_read_mip: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_read_mip: fname = %d; invalid parameter\n", fname); + if (setjmp(dmx->jump)) + goto done; + dmx->fname = fname; + dmx->fp = NULL; + dmx->count = 0; + dmx->c = '\n'; + dmx->field[0] = '\0'; + dmx->empty = dmx->nonint = 0; + xprintf("Reading MIP solution from '%s'...\n", fname); + dmx->fp = glp_open(fname, "r"); + if (dmx->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* read solution line */ + dmx_read_designator(dmx); + if (strcmp(dmx->field, "s") != 0) + dmx_error(dmx, "solution line missing or invalid"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "mip") != 0) + dmx_error(dmx, "wrong solution designator; 'mip' expected"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &m) == 0 && m >= 0)) + dmx_error(dmx, "number of rows missing or invalid"); + if (m != P->m) + dmx_error(dmx, "number of rows mismatch"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &n) == 0 && n >= 0)) + dmx_error(dmx, "number of columns missing or invalid"); + if (n != P->n) + dmx_error(dmx, "number of columns mismatch"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "o") == 0) + sst = GLP_OPT; + else if (strcmp(dmx->field, "f") == 0) + sst = GLP_FEAS; + else if (strcmp(dmx->field, "n") == 0) + sst = GLP_NOFEAS; + else if (strcmp(dmx->field, "u") == 0) + sst = GLP_UNDEF; + else + dmx_error(dmx, "solution status missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &obj) != 0) + dmx_error(dmx, "objective value missing or invalid"); + dmx_end_of_line(dmx); + /* allocate working arrays */ + stat = xalloc(1+m+n, sizeof(stat[0])); + for (k = 1; k <= m+n; k++) + stat[k] = '?'; + prim = xalloc(1+m+n, sizeof(prim[0])); + /* read solution descriptor lines */ + for (;;) + { dmx_read_designator(dmx); + if (strcmp(dmx->field, "i") == 0) + { /* row solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &i) != 0) + dmx_error(dmx, "row number missing or invalid"); + if (!(1 <= i && i <= m)) + dmx_error(dmx, "row number out of range"); + if (stat[i] != '?') + dmx_error(dmx, "duplicate row solution descriptor"); + stat[i] = GLP_BS; + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[i]) != 0) + dmx_error(dmx, "row value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "j") == 0) + { /* column solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &j) != 0) + dmx_error(dmx, "column number missing or invalid"); + if (!(1 <= j && j <= n)) + dmx_error(dmx, "column number out of range"); + if (stat[m+j] != '?') + dmx_error(dmx, "duplicate column solution descriptor"); + stat[m+j] = GLP_BS; + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[m+j]) != 0) + dmx_error(dmx, "column value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "e") == 0) + break; + else + dmx_error(dmx, "line designator missing or invalid"); + dmx_end_of_line(dmx); + } + /* store solution components into problem object */ + for (k = 1; k <= m+n; k++) + { if (stat[k] == '?') + dmx_error(dmx, "incomplete MIP solution"); + } + P->mip_stat = sst; + P->mip_obj = obj; + for (i = 1; i <= m; i++) + P->row[i]->mipx = prim[i]; + for (j = 1; j <= n; j++) + P->col[j]->mipx = prim[m+j]; + /* MIP solution has been successfully read */ + xprintf("%d lines were read\n", dmx->count); + ret = 0; +done: if (dmx->fp != NULL) + glp_close(dmx->fp); + if (stat != NULL) + xfree(stat); + if (prim != NULL) + xfree(prim); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdprob.c b/glpk-5.0/src/api/rdprob.c new file mode 100644 index 0000000..306f0a8 --- /dev/null +++ b/glpk-5.0/src/api/rdprob.c @@ -0,0 +1,375 @@ +/* rdprob.c (read problem data in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "misc.h" +#include "prob.h" + +#define xfprintf glp_format +#define error dmx_error +#define warning dmx_warning +#define read_char dmx_read_char +#define read_designator dmx_read_designator +#define read_field dmx_read_field +#define end_of_line dmx_end_of_line +#define check_int dmx_check_int + +/*********************************************************************** +* NAME +* +* glp_read_prob - read problem data in GLPK format +* +* SYNOPSIS +* +* int glp_read_prob(glp_prob *P, int flags, const char *fname); +* +* The routine glp_read_prob reads problem data in GLPK LP/MIP format +* from a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_prob(glp_prob *P, int flags, const char *fname) +{ DMX _csa, *csa = &_csa; + int mip, m, n, nnz, ne, i, j, k, type, kind, ret, *ln = NULL, + *ia = NULL, *ja = NULL; + double lb, ub, temp, *ar = NULL; + char *rf = NULL, *cf = NULL; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_read_prob: P = %p; invalid problem object\n", + P); +#endif + if (flags != 0) + xerror("glp_read_prob: flags = %d; invalid parameter\n", + flags); + if (fname == NULL) + xerror("glp_read_prob: fname = %d; invalid parameter\n", + fname); + glp_erase_prob(P); + if (setjmp(csa->jump)) + { ret = 1; + goto done; + } + csa->fname = fname; + csa->fp = NULL; + csa->count = 0; + csa->c = '\n'; + csa->field[0] = '\0'; + csa->empty = csa->nonint = 0; + xprintf("Reading problem data from '%s'...\n", fname); + csa->fp = glp_open(fname, "r"); + if (csa->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + longjmp(csa->jump, 1); + } + /* read problem line */ + read_designator(csa); + if (strcmp(csa->field, "p") != 0) + error(csa, "problem line missing or invalid"); + read_field(csa); + if (strcmp(csa->field, "lp") == 0) + mip = 0; + else if (strcmp(csa->field, "mip") == 0) + mip = 1; + else + error(csa, "wrong problem designator; 'lp' or 'mip' expected"); + read_field(csa); + if (strcmp(csa->field, "min") == 0) + glp_set_obj_dir(P, GLP_MIN); + else if (strcmp(csa->field, "max") == 0) + glp_set_obj_dir(P, GLP_MAX); + else + error(csa, "objective sense missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &m) == 0 && m >= 0)) + error(csa, "number of rows missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &n) == 0 && n >= 0)) + error(csa, "number of columns missing or invalid"); + read_field(csa); + if (!(str2int(csa->field, &nnz) == 0 && nnz >= 0)) + error(csa, "number of constraint coefficients missing or inval" + "id"); + if (m > 0) + { glp_add_rows(P, m); + for (i = 1; i <= m; i++) + glp_set_row_bnds(P, i, GLP_FX, 0.0, 0.0); + } + if (n > 0) + { glp_add_cols(P, n); + for (j = 1; j <= n; j++) + { if (!mip) + glp_set_col_bnds(P, j, GLP_LO, 0.0, 0.0); + else + glp_set_col_kind(P, j, GLP_BV); + } + } + end_of_line(csa); + /* allocate working arrays */ + rf = xcalloc(1+m, sizeof(char)); + memset(rf, 0, 1+m); + cf = xcalloc(1+n, sizeof(char)); + memset(cf, 0, 1+n); + ln = xcalloc(1+nnz, sizeof(int)); + ia = xcalloc(1+nnz, sizeof(int)); + ja = xcalloc(1+nnz, sizeof(int)); + ar = xcalloc(1+nnz, sizeof(double)); + /* read descriptor lines */ + ne = 0; + for (;;) + { read_designator(csa); + if (strcmp(csa->field, "i") == 0) + { /* row descriptor */ + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "row number missing or invalid"); + if (!(1 <= i && i <= m)) + error(csa, "row number out of range"); + read_field(csa); + if (strcmp(csa->field, "f") == 0) + type = GLP_FR; + else if (strcmp(csa->field, "l") == 0) + type = GLP_LO; + else if (strcmp(csa->field, "u") == 0) + type = GLP_UP; + else if (strcmp(csa->field, "d") == 0) + type = GLP_DB; + else if (strcmp(csa->field, "s") == 0) + type = GLP_FX; + else + error(csa, "row type missing or invalid"); + if (type == GLP_LO || type == GLP_DB || type == GLP_FX) + { read_field(csa); + if (str2num(csa->field, &lb) != 0) + error(csa, "row lower bound/fixed value missing or in" + "valid"); + } + else + lb = 0.0; + if (type == GLP_UP || type == GLP_DB) + { read_field(csa); + if (str2num(csa->field, &ub) != 0) + error(csa, "row upper bound missing or invalid"); + } + else + ub = 0.0; + if (rf[i] & 0x01) + error(csa, "duplicate row descriptor"); + glp_set_row_bnds(P, i, type, lb, ub), rf[i] |= 0x01; + } + else if (strcmp(csa->field, "j") == 0) + { /* column descriptor */ + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "column number missing or invalid"); + if (!(1 <= j && j <= n)) + error(csa, "column number out of range"); + if (!mip) + kind = GLP_CV; + else + { read_field(csa); + if (strcmp(csa->field, "c") == 0) + kind = GLP_CV; + else if (strcmp(csa->field, "i") == 0) + kind = GLP_IV; + else if (strcmp(csa->field, "b") == 0) + { kind = GLP_IV; + type = GLP_DB, lb = 0.0, ub = 1.0; + goto skip; + } + else + error(csa, "column kind missing or invalid"); + } + read_field(csa); + if (strcmp(csa->field, "f") == 0) + type = GLP_FR; + else if (strcmp(csa->field, "l") == 0) + type = GLP_LO; + else if (strcmp(csa->field, "u") == 0) + type = GLP_UP; + else if (strcmp(csa->field, "d") == 0) + type = GLP_DB; + else if (strcmp(csa->field, "s") == 0) + type = GLP_FX; + else + error(csa, "column type missing or invalid"); + if (type == GLP_LO || type == GLP_DB || type == GLP_FX) + { read_field(csa); + if (str2num(csa->field, &lb) != 0) + error(csa, "column lower bound/fixed value missing or" + " invalid"); + } + else + lb = 0.0; + if (type == GLP_UP || type == GLP_DB) + { read_field(csa); + if (str2num(csa->field, &ub) != 0) + error(csa, "column upper bound missing or invalid"); + } + else + ub = 0.0; +skip: if (cf[j] & 0x01) + error(csa, "duplicate column descriptor"); + glp_set_col_kind(P, j, kind); + glp_set_col_bnds(P, j, type, lb, ub), cf[j] |= 0x01; + } + else if (strcmp(csa->field, "a") == 0) + { /* coefficient descriptor */ + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "row number missing or invalid"); + if (!(0 <= i && i <= m)) + error(csa, "row number out of range"); + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "column number missing or invalid"); + if (!((i == 0 ? 0 : 1) <= j && j <= n)) + error(csa, "column number out of range"); + read_field(csa); + if (i == 0) + { if (str2num(csa->field, &temp) != 0) + error(csa, "objective %s missing or invalid", + j == 0 ? "constant term" : "coefficient"); + if (cf[j] & 0x10) + error(csa, "duplicate objective %s", + j == 0 ? "constant term" : "coefficient"); + glp_set_obj_coef(P, j, temp), cf[j] |= 0x10; + } + else + { if (str2num(csa->field, &temp) != 0) + error(csa, "constraint coefficient missing or invalid" + ); + if (ne == nnz) + error(csa, "too many constraint coefficient descripto" + "rs"); + ln[++ne] = csa->count; + ia[ne] = i, ja[ne] = j, ar[ne] = temp; + } + } + else if (strcmp(csa->field, "n") == 0) + { /* symbolic name descriptor */ + read_field(csa); + if (strcmp(csa->field, "p") == 0) + { /* problem name */ + read_field(csa); + if (P->name != NULL) + error(csa, "duplicate problem name"); + glp_set_prob_name(P, csa->field); + } + else if (strcmp(csa->field, "z") == 0) + { /* objective name */ + read_field(csa); + if (P->obj != NULL) + error(csa, "duplicate objective name"); + glp_set_obj_name(P, csa->field); + } + else if (strcmp(csa->field, "i") == 0) + { /* row name */ + read_field(csa); + if (str2int(csa->field, &i) != 0) + error(csa, "row number missing or invalid"); + if (!(1 <= i && i <= m)) + error(csa, "row number out of range"); + read_field(csa); + if (P->row[i]->name != NULL) + error(csa, "duplicate row name"); + glp_set_row_name(P, i, csa->field); + } + else if (strcmp(csa->field, "j") == 0) + { /* column name */ + read_field(csa); + if (str2int(csa->field, &j) != 0) + error(csa, "column number missing or invalid"); + if (!(1 <= j && j <= n)) + error(csa, "column number out of range"); + read_field(csa); + if (P->col[j]->name != NULL) + error(csa, "duplicate column name"); + glp_set_col_name(P, j, csa->field); + } + else + error(csa, "object designator missing or invalid"); + } + else if (strcmp(csa->field, "e") == 0) + break; + else + error(csa, "line designator missing or invalid"); + end_of_line(csa); + } + if (ne < nnz) + error(csa, "too few constraint coefficient descriptors"); + xassert(ne == nnz); + k = glp_check_dup(m, n, ne, ia, ja); + xassert(0 <= k && k <= nnz); + if (k > 0) + { csa->count = ln[k]; + error(csa, "duplicate constraint coefficient"); + } + glp_load_matrix(P, ne, ia, ja, ar); + /* print some statistics */ + if (P->name != NULL) + xprintf("Problem: %s\n", P->name); + if (P->obj != NULL) + xprintf("Objective: %s\n", P->obj); + xprintf("%d row%s, %d column%s, %d non-zero%s\n", + m, m == 1 ? "" : "s", n, n == 1 ? "" : "s", nnz, nnz == 1 ? + "" : "s"); + if (glp_get_num_int(P) > 0) + { int ni = glp_get_num_int(P); + int nb = glp_get_num_bin(P); + if (ni == 1) + { if (nb == 0) + xprintf("One variable is integer\n"); + else + xprintf("One variable is binary\n"); + } + else + { xprintf("%d integer variables, ", ni); + if (nb == 0) + xprintf("none"); + else if (nb == 1) + xprintf("one"); + else if (nb == ni) + xprintf("all"); + else + xprintf("%d", nb); + xprintf(" of which %s binary\n", nb == 1 ? "is" : "are"); + } + } + xprintf("%d lines were read\n", csa->count); + /* problem data has been successfully read */ + glp_sort_matrix(P); + ret = 0; +done: if (csa->fp != NULL) glp_close(csa->fp); + if (rf != NULL) xfree(rf); + if (cf != NULL) xfree(cf); + if (ln != NULL) xfree(ln); + if (ia != NULL) xfree(ia); + if (ja != NULL) xfree(ja); + if (ar != NULL) xfree(ar); + if (ret) glp_erase_prob(P); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rdsol.c b/glpk-5.0/src/api/rdsol.c new file mode 100644 index 0000000..dcd8bf3 --- /dev/null +++ b/glpk-5.0/src/api/rdsol.c @@ -0,0 +1,223 @@ +/* rdsol.c (read basic solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "dimacs.h" +#include "env.h" +#include "misc.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_read_sol - read basic solution in GLPK format +* +* SYNOPSIS +* +* int glp_read_sol(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_read_sol reads basic solution from a text file in +* GLPK format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_read_sol(glp_prob *P, const char *fname) +{ DMX dmx_, *dmx = &dmx_; + int i, j, k, m, n, pst, dst, ret = 1; + char *stat = NULL; + double obj, *prim = NULL, *dual = NULL; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_read_sol: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_read_sol: fname = %d; invalid parameter\n", fname); + if (setjmp(dmx->jump)) + goto done; + dmx->fname = fname; + dmx->fp = NULL; + dmx->count = 0; + dmx->c = '\n'; + dmx->field[0] = '\0'; + dmx->empty = dmx->nonint = 0; + xprintf("Reading basic solution from '%s'...\n", fname); + dmx->fp = glp_open(fname, "r"); + if (dmx->fp == NULL) + { xprintf("Unable to open '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* read solution line */ + dmx_read_designator(dmx); + if (strcmp(dmx->field, "s") != 0) + dmx_error(dmx, "solution line missing or invalid"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "bas") != 0) + dmx_error(dmx, "wrong solution designator; 'bas' expected"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &m) == 0 && m >= 0)) + dmx_error(dmx, "number of rows missing or invalid"); + if (m != P->m) + dmx_error(dmx, "number of rows mismatch"); + dmx_read_field(dmx); + if (!(str2int(dmx->field, &n) == 0 && n >= 0)) + dmx_error(dmx, "number of columns missing or invalid"); + if (n != P->n) + dmx_error(dmx, "number of columns mismatch"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "u") == 0) + pst = GLP_UNDEF; + else if (strcmp(dmx->field, "f") == 0) + pst = GLP_FEAS; + else if (strcmp(dmx->field, "i") == 0) + pst = GLP_INFEAS; + else if (strcmp(dmx->field, "n") == 0) + pst = GLP_NOFEAS; + else + dmx_error(dmx, "primal solution status missing or invalid"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "u") == 0) + dst = GLP_UNDEF; + else if (strcmp(dmx->field, "f") == 0) + dst = GLP_FEAS; + else if (strcmp(dmx->field, "i") == 0) + dst = GLP_INFEAS; + else if (strcmp(dmx->field, "n") == 0) + dst = GLP_NOFEAS; + else + dmx_error(dmx, "dual solution status missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &obj) != 0) + dmx_error(dmx, "objective value missing or invalid"); + dmx_end_of_line(dmx); + /* allocate working arrays */ + stat = xalloc(1+m+n, sizeof(stat[0])); + for (k = 1; k <= m+n; k++) + stat[k] = '?'; + prim = xalloc(1+m+n, sizeof(prim[0])); + dual = xalloc(1+m+n, sizeof(dual[0])); + /* read solution descriptor lines */ + for (;;) + { dmx_read_designator(dmx); + if (strcmp(dmx->field, "i") == 0) + { /* row solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &i) != 0) + dmx_error(dmx, "row number missing or invalid"); + if (!(1 <= i && i <= m)) + dmx_error(dmx, "row number out of range"); + if (stat[i] != '?') + dmx_error(dmx, "duplicate row solution descriptor"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "b") == 0) + stat[i] = GLP_BS; + else if (strcmp(dmx->field, "l") == 0) + stat[i] = GLP_NL; + else if (strcmp(dmx->field, "u") == 0) + stat[i] = GLP_NU; + else if (strcmp(dmx->field, "f") == 0) + stat[i] = GLP_NF; + else if (strcmp(dmx->field, "s") == 0) + stat[i] = GLP_NS; + else + dmx_error(dmx, "row status missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[i]) != 0) + dmx_error(dmx, "row primal value missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &dual[i]) != 0) + dmx_error(dmx, "row dual value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "j") == 0) + { /* column solution descriptor */ + dmx_read_field(dmx); + if (str2int(dmx->field, &j) != 0) + dmx_error(dmx, "column number missing or invalid"); + if (!(1 <= j && j <= n)) + dmx_error(dmx, "column number out of range"); + if (stat[m+j] != '?') + dmx_error(dmx, "duplicate column solution descriptor"); + dmx_read_field(dmx); + if (strcmp(dmx->field, "b") == 0) + stat[m+j] = GLP_BS; + else if (strcmp(dmx->field, "l") == 0) + stat[m+j] = GLP_NL; + else if (strcmp(dmx->field, "u") == 0) + stat[m+j] = GLP_NU; + else if (strcmp(dmx->field, "f") == 0) + stat[m+j] = GLP_NF; + else if (strcmp(dmx->field, "s") == 0) + stat[m+j] = GLP_NS; + else + dmx_error(dmx, "column status missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &prim[m+j]) != 0) + dmx_error(dmx, "column primal value missing or invalid"); + dmx_read_field(dmx); + if (str2num(dmx->field, &dual[m+j]) != 0) + dmx_error(dmx, "column dual value missing or invalid"); + dmx_end_of_line(dmx); + } + else if (strcmp(dmx->field, "e") == 0) + break; + else + dmx_error(dmx, "line designator missing or invalid"); + dmx_end_of_line(dmx); + } + /* store solution components into problem object */ + for (k = 1; k <= m+n; k++) + { if (stat[k] == '?') + dmx_error(dmx, "incomplete basic solution"); + } + P->pbs_stat = pst; + P->dbs_stat = dst; + P->obj_val = obj; + P->it_cnt = 0; + P->some = 0; + for (i = 1; i <= m; i++) + { glp_set_row_stat(P, i, stat[i]); + P->row[i]->prim = prim[i]; + P->row[i]->dual = dual[i]; + } + for (j = 1; j <= n; j++) + { glp_set_col_stat(P, j, stat[m+j]); + P->col[j]->prim = prim[m+j]; + P->col[j]->dual = dual[m+j]; + } + /* basic solution has been successfully read */ + xprintf("%d lines were read\n", dmx->count); + ret = 0; +done: if (dmx->fp != NULL) + glp_close(dmx->fp); + if (stat != NULL) + xfree(stat); + if (prim != NULL) + xfree(prim); + if (dual != NULL) + xfree(dual); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/rmfgen.c b/glpk-5.0/src/api/rmfgen.c new file mode 100644 index 0000000..c98c82c --- /dev/null +++ b/glpk-5.0/src/api/rmfgen.c @@ -0,0 +1,20 @@ +/* rmfgen.c */ + +#include "env.h" +#include "glpk.h" + +int glp_rmfgen(glp_graph *G_, int *s_, int *t_, int a_cap_, + const int parm[1+5]) +{ static const char func[] = "glp_rmfgen"; + xassert(G_ == G_); + xassert(s_ == s_); + xassert(t_ == t_); + xassert(a_cap_ == a_cap_); + xassert(parm == parm); + xerror("%s: sorry, this routine is temporarily disabled due to li" + "censing problems\n", func); + abort(); + return -1; +} + +/* eof */ diff --git a/glpk-5.0/src/api/strong.c b/glpk-5.0/src/api/strong.c new file mode 100644 index 0000000..8921f5e --- /dev/null +++ b/glpk-5.0/src/api/strong.c @@ -0,0 +1,108 @@ +/* strong.c (find all strongly connected components of graph) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "mc13d.h" + +/*********************************************************************** +* NAME +* +* glp_strong_comp - find all strongly connected components of graph +* +* SYNOPSIS +* +* int glp_strong_comp(glp_graph *G, int v_num); +* +* DESCRIPTION +* +* The routine glp_strong_comp finds all strongly connected components +* of the specified graph. +* +* The parameter v_num specifies an offset of the field of type int +* in the vertex data block, to which the routine stores the number of +* a strongly connected component containing that vertex. If v_num < 0, +* no component numbers are stored. +* +* The components are numbered in arbitrary order from 1 to nc, where +* nc is the total number of components found, 0 <= nc <= |V|. However, +* the component numbering has the property that for every arc (i->j) +* in the graph the condition num(i) >= num(j) holds. +* +* RETURNS +* +* The routine returns nc, the total number of components found. */ + +int glp_strong_comp(glp_graph *G, int v_num) +{ glp_vertex *v; + glp_arc *a; + int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl, + *numb, *prev; + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) + xerror("glp_strong_comp: v_num = %d; invalid offset\n", + v_num); + n = G->nv; + if (n == 0) + { nc = 0; + goto done; + } + na = G->na; + icn = xcalloc(1+na, sizeof(int)); + ip = xcalloc(1+n, sizeof(int)); + lenr = xcalloc(1+n, sizeof(int)); + ior = xcalloc(1+n, sizeof(int)); + ib = xcalloc(1+n, sizeof(int)); + lowl = xcalloc(1+n, sizeof(int)); + numb = xcalloc(1+n, sizeof(int)); + prev = xcalloc(1+n, sizeof(int)); + k = 1; + for (i = 1; i <= n; i++) + { v = G->v[i]; + ip[i] = k; + for (a = v->out; a != NULL; a = a->t_next) + icn[k++] = a->head->i; + lenr[i] = k - ip[i]; + } + xassert(na == k-1); + nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev); + if (v_num >= 0) + { xassert(ib[1] == 1); + for (k = 1; k <= nc; k++) + { last = (k < nc ? ib[k+1] : n+1); + xassert(ib[k] < last); + for (i = ib[k]; i < last; i++) + { v = G->v[ior[i]]; + memcpy((char *)v->data + v_num, &k, sizeof(int)); + } + } + } + xfree(icn); + xfree(ip); + xfree(lenr); + xfree(ior); + xfree(ib); + xfree(lowl); + xfree(numb); + xfree(prev); +done: return nc; +} + +/* eof */ diff --git a/glpk-5.0/src/api/topsort.c b/glpk-5.0/src/api/topsort.c new file mode 100644 index 0000000..d7aa7cc --- /dev/null +++ b/glpk-5.0/src/api/topsort.c @@ -0,0 +1,121 @@ +/* topsort.c (topological sorting of acyclic digraph) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_top_sort - topological sorting of acyclic digraph +* +* SYNOPSIS +* +* int glp_top_sort(glp_graph *G, int v_num); +* +* DESCRIPTION +* +* The routine glp_top_sort performs topological sorting of vertices of +* the specified acyclic digraph. +* +* The parameter v_num specifies an offset of the field of type int in +* the vertex data block, to which the routine stores the vertex number +* assigned. If v_num < 0, vertex numbers are not stored. +* +* The vertices are numbered from 1 to n, where n is the total number +* of vertices in the graph. The vertex numbering has the property that +* for every arc (i->j) in the graph the condition num(i) < num(j) +* holds. Special case num(i) = 0 means that vertex i is not assigned a +* number, because the graph is *not* acyclic. +* +* RETURNS +* +* If the graph is acyclic and therefore all the vertices have been +* assigned numbers, the routine glp_top_sort returns zero. Otherwise, +* if the graph is not acyclic, the routine returns the number of +* vertices which have not been numbered, i.e. for which num(i) = 0. */ + +static int top_sort(glp_graph *G, int num[]) +{ glp_arc *a; + int i, j, cnt, top, *stack, *indeg; + /* allocate working arrays */ + indeg = xcalloc(1+G->nv, sizeof(int)); + stack = xcalloc(1+G->nv, sizeof(int)); + /* determine initial indegree of each vertex; push into the stack + the vertices having zero indegree */ + top = 0; + for (i = 1; i <= G->nv; i++) + { num[i] = indeg[i] = 0; + for (a = G->v[i]->in; a != NULL; a = a->h_next) + indeg[i]++; + if (indeg[i] == 0) + stack[++top] = i; + } + /* assign numbers to vertices in the sorted order */ + cnt = 0; + while (top > 0) + { /* pull vertex i from the stack */ + i = stack[top--]; + /* it has zero indegree in the current graph */ + xassert(indeg[i] == 0); + /* so assign it a next number */ + xassert(num[i] == 0); + num[i] = ++cnt; + /* remove vertex i from the current graph, update indegree of + its adjacent vertices, and push into the stack new vertices + whose indegree becomes zero */ + for (a = G->v[i]->out; a != NULL; a = a->t_next) + { j = a->head->i; + /* there exists arc (i->j) in the graph */ + xassert(indeg[j] > 0); + indeg[j]--; + if (indeg[j] == 0) + stack[++top] = j; + } + } + /* free working arrays */ + xfree(indeg); + xfree(stack); + return G->nv - cnt; +} + +int glp_top_sort(glp_graph *G, int v_num) +{ glp_vertex *v; + int i, cnt, *num; + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) + xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num); + if (G->nv == 0) + { cnt = 0; + goto done; + } + num = xcalloc(1+G->nv, sizeof(int)); + cnt = top_sort(G, num); + if (v_num >= 0) + { for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_num, &num[i], sizeof(int)); + } + } + xfree(num); +done: return cnt; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wcliqex.c b/glpk-5.0/src/api/wcliqex.c new file mode 100644 index 0000000..7008b95 --- /dev/null +++ b/glpk-5.0/src/api/wcliqex.c @@ -0,0 +1,120 @@ +/* wcliqex.c (find maximum weight clique with exact algorithm) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" +#include "wclique.h" + +static void set_edge(int nv, unsigned char a[], int i, int j) +{ int k; + xassert(1 <= j && j < i && i <= nv); + k = ((i - 1) * (i - 2)) / 2 + (j - 1); + a[k / CHAR_BIT] |= + (unsigned char)(1 << ((CHAR_BIT - 1) - k % CHAR_BIT)); + return; +} + +int glp_wclique_exact(glp_graph *G, int v_wgt, double *sol, int v_set) +{ /* find maximum weight clique with exact algorithm */ + glp_arc *e; + int i, j, k, len, x, *w, *ind, ret = 0; + unsigned char *a; + double s, t; + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) + xerror("glp_wclique_exact: v_wgt = %d; invalid parameter\n", + v_wgt); + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_wclique_exact: v_set = %d; invalid parameter\n", + v_set); + if (G->nv == 0) + { /* empty graph has only empty clique */ + if (sol != NULL) *sol = 0.0; + return 0; + } + /* allocate working arrays */ + w = xcalloc(1+G->nv, sizeof(int)); + ind = xcalloc(1+G->nv, sizeof(int)); + len = G->nv; /* # vertices */ + len = len * (len - 1) / 2; /* # entries in lower triangle */ + len = (len + (CHAR_BIT - 1)) / CHAR_BIT; /* # bytes needed */ + a = xcalloc(len, sizeof(char)); + memset(a, 0, len * sizeof(char)); + /* determine vertex weights */ + s = 0.0; + for (i = 1; i <= G->nv; i++) + { if (v_wgt >= 0) + { memcpy(&t, (char *)G->v[i]->data + v_wgt, sizeof(double)); + if (!(0.0 <= t && t <= (double)INT_MAX && t == floor(t))) + { ret = GLP_EDATA; + goto done; + } + w[i] = (int)t; + } + else + w[i] = 1; + s += (double)w[i]; + } + if (s > (double)INT_MAX) + { ret = GLP_EDATA; + goto done; + } + /* build the adjacency matrix */ + for (i = 1; i <= G->nv; i++) + { for (e = G->v[i]->in; e != NULL; e = e->h_next) + { j = e->tail->i; + /* there exists edge (j,i) in the graph */ + if (i > j) set_edge(G->nv, a, i, j); + } + for (e = G->v[i]->out; e != NULL; e = e->t_next) + { j = e->head->i; + /* there exists edge (i,j) in the graph */ + if (i > j) set_edge(G->nv, a, i, j); + } + } + /* find maximum weight clique in the graph */ + len = wclique(G->nv, w, a, ind); + /* compute the clique weight */ + s = 0.0; + for (k = 1; k <= len; k++) + { i = ind[k]; + xassert(1 <= i && i <= G->nv); + s += (double)w[i]; + } + if (sol != NULL) *sol = s; + /* mark vertices included in the clique */ + if (v_set >= 0) + { x = 0; + for (i = 1; i <= G->nv; i++) + memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); + x = 1; + for (k = 1; k <= len; k++) + { i = ind[k]; + memcpy((char *)G->v[i]->data + v_set, &x, sizeof(int)); + } + } +done: /* free working arrays */ + xfree(w); + xfree(ind); + xfree(a); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/weak.c b/glpk-5.0/src/api/weak.c new file mode 100644 index 0000000..a34d5a7 --- /dev/null +++ b/glpk-5.0/src/api/weak.c @@ -0,0 +1,148 @@ +/* weak.c (find all weakly connected components of graph) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +/*********************************************************************** +* NAME +* +* glp_weak_comp - find all weakly connected components of graph +* +* SYNOPSIS +* +* int glp_weak_comp(glp_graph *G, int v_num); +* +* DESCRIPTION +* +* The routine glp_weak_comp finds all weakly connected components of +* the specified graph. +* +* The parameter v_num specifies an offset of the field of type int +* in the vertex data block, to which the routine stores the number of +* a (weakly) connected component containing that vertex. If v_num < 0, +* no component numbers are stored. +* +* The components are numbered in arbitrary order from 1 to nc, where +* nc is the total number of components found, 0 <= nc <= |V|. +* +* RETURNS +* +* The routine returns nc, the total number of components found. */ + +int glp_weak_comp(glp_graph *G, int v_num) +{ glp_vertex *v; + glp_arc *a; + int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list; + if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int)) + xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num); + nv = G->nv; + if (nv == 0) + { nc = 0; + goto done; + } + /* allocate working arrays */ + prev = xcalloc(1+nv, sizeof(int)); + next = xcalloc(1+nv, sizeof(int)); + list = xcalloc(1+nv, sizeof(int)); + /* if vertex i is unlabelled, prev[i] is the index of previous + unlabelled vertex, and next[i] is the index of next unlabelled + vertex; if vertex i is labelled, then prev[i] < 0, and next[i] + is the connected component number */ + /* initially all vertices are unlabelled */ + f = 1; + for (i = 1; i <= nv; i++) + prev[i] = i - 1, next[i] = i + 1; + next[nv] = 0; + /* main loop (until all vertices have been labelled) */ + nc = 0; + while (f != 0) + { /* take an unlabelled vertex */ + i = f; + /* and remove it from the list of unlabelled vertices */ + f = next[i]; + if (f != 0) prev[f] = 0; + /* label the vertex; it begins a new component */ + prev[i] = -1, next[i] = ++nc; + /* breadth first search */ + list[1] = i, pos1 = pos2 = 1; + while (pos1 <= pos2) + { /* dequeue vertex i */ + i = list[pos1++]; + /* consider all arcs incoming to vertex i */ + for (a = G->v[i]->in; a != NULL; a = a->h_next) + { /* vertex j is adjacent to vertex i */ + j = a->tail->i; + if (prev[j] >= 0) + { /* vertex j is unlabelled */ + /* remove it from the list of unlabelled vertices */ + if (prev[j] == 0) + f = next[j]; + else + next[prev[j]] = next[j]; + if (next[j] == 0) + ; + else + prev[next[j]] = prev[j]; + /* label the vertex */ + prev[j] = -1, next[j] = nc; + /* and enqueue it for further consideration */ + list[++pos2] = j; + } + } + /* consider all arcs outgoing from vertex i */ + for (a = G->v[i]->out; a != NULL; a = a->t_next) + { /* vertex j is adjacent to vertex i */ + j = a->head->i; + if (prev[j] >= 0) + { /* vertex j is unlabelled */ + /* remove it from the list of unlabelled vertices */ + if (prev[j] == 0) + f = next[j]; + else + next[prev[j]] = next[j]; + if (next[j] == 0) + ; + else + prev[next[j]] = prev[j]; + /* label the vertex */ + prev[j] = -1, next[j] = nc; + /* and enqueue it for further consideration */ + list[++pos2] = j; + } + } + } + } + /* store component numbers */ + if (v_num >= 0) + { for (i = 1; i <= nv; i++) + { v = G->v[i]; + memcpy((char *)v->data + v_num, &next[i], sizeof(int)); + } + } + /* free working arrays */ + xfree(prev); + xfree(next); + xfree(list); +done: return nc; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrasn.c b/glpk-5.0/src/api/wrasn.c new file mode 100644 index 0000000..0f60d8e --- /dev/null +++ b/glpk-5.0/src/api/wrasn.c @@ -0,0 +1,105 @@ +/* wrasn.c (write assignment problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_write_asnprob - write assignment problem data in DIMACS format +* +* SYNOPSIS +* +* int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_asnprob writes assignment problem data in +* DIMACS format to a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_asnprob(glp_graph *G, int v_set, int a_cost, const char + *fname) +{ glp_file *fp; + glp_vertex *v; + glp_arc *a; + int i, k, count = 0, ret; + double cost; + if (v_set >= 0 && v_set > G->v_size - (int)sizeof(int)) + xerror("glp_write_asnprob: v_set = %d; invalid offset\n", + v_set); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_write_asnprob: a_cost = %d; invalid offset\n", + a_cost); + xprintf("Writing assignment problem data to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "c %s\n", + G->name == NULL ? "unknown" : G->name), count++; + xfprintf(fp, "p asn %d %d\n", G->nv, G->na), count++; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + if (v_set >= 0) + memcpy(&k, (char *)v->data + v_set, sizeof(int)); + else + k = (v->out != NULL ? 0 : 1); + if (k == 0) + xfprintf(fp, "n %d\n", i), count++; + } + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 1.0; + xfprintf(fp, "a %d %d %.*g\n", + a->tail->i, a->head->i, DBL_DIG, cost), count++; + } + } + xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrcc.c b/glpk-5.0/src/api/wrcc.c new file mode 100644 index 0000000..cf1356b --- /dev/null +++ b/glpk-5.0/src/api/wrcc.c @@ -0,0 +1,100 @@ +/* wrcc.c (write graph in DIMACS clique/coloring format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_write_ccdata - write graph in DIMACS clique/coloring format +* +* SYNOPSIS +* +* int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_ccdata writes the specified graph in DIMACS +* clique/coloring format to a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_ccdata(glp_graph *G, int v_wgt, const char *fname) +{ glp_file *fp; + glp_vertex *v; + glp_arc *e; + int i, count = 0, ret; + double w; + if (v_wgt >= 0 && v_wgt > G->v_size - (int)sizeof(double)) + xerror("glp_write_ccdata: v_wgt = %d; invalid offset\n", + v_wgt); + xprintf("Writing graph to '%s'\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "c %s\n", + G->name == NULL ? "unknown" : G->name), count++; + xfprintf(fp, "p edge %d %d\n", G->nv, G->na), count++; + if (v_wgt >= 0) + { for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + memcpy(&w, (char *)v->data + v_wgt, sizeof(double)); + if (w != 1.0) + xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, w), count++; + } + } + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (e = v->out; e != NULL; e = e->t_next) + xfprintf(fp, "e %d %d\n", e->tail->i, e->head->i), count++; + } + xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/**********************************************************************/ + +int glp_write_graph(glp_graph *G, const char *fname) +{ return + glp_write_ccdata(G, -1, fname); +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrcnf.c b/glpk-5.0/src/api/wrcnf.c new file mode 100644 index 0000000..fc41fa2 --- /dev/null +++ b/glpk-5.0/src/api/wrcnf.c @@ -0,0 +1,85 @@ +/* wrcnf.c (write CNF-SAT problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +int glp_write_cnfsat(glp_prob *P, const char *fname) +{ /* write CNF-SAT problem data in DIMACS format */ + glp_file *fp = NULL; + GLPAIJ *aij; + int i, j, len, count = 0, ret; + char s[50]; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_write_cnfsat: P = %p; invalid problem object\n", + P); +#endif + if (glp_check_cnfsat(P) != 0) + { xprintf("glp_write_cnfsat: problem object does not encode CNF-" + "SAT instance\n"); + ret = 1; + goto done; + } + xprintf("Writing CNF-SAT problem data to '%s'...\n", fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "c %s\n", + P->name == NULL ? "unknown" : P->name), count++; + xfprintf(fp, "p cnf %d %d\n", P->n, P->m), count++; + for (i = 1; i <= P->m; i++) + { len = 0; + for (aij = P->row[i]->ptr; aij != NULL; aij = aij->r_next) + { j = aij->col->j; + if (aij->val < 0.0) j = -j; + sprintf(s, "%d", j); + if (len > 0 && len + 1 + strlen(s) > 72) + xfprintf(fp, "\n"), count++, len = 0; + xfprintf(fp, "%s%s", len == 0 ? "" : " ", s); + if (len > 0) len++; + len += strlen(s); + } + if (len > 0 && len + 1 + 1 > 72) + xfprintf(fp, "\n"), count++, len = 0; + xfprintf(fp, "%s0\n", len == 0 ? "" : " "), count++; + } + xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wript.c b/glpk-5.0/src/api/wript.c new file mode 100644 index 0000000..f7f18fe --- /dev/null +++ b/glpk-5.0/src/api/wript.c @@ -0,0 +1,122 @@ +/* wript.c (write interior-point solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_write_ipt - write interior-point solution in GLPK format +* +* SYNOPSIS +* +* int glp_write_ipt(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_ipt writes interior-point solution to a text +* file in GLPK format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_ipt(glp_prob *P, const char *fname) +{ glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, count, ret = 1; + char *s; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_write_ipt: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_write_ipt: fname = %d; invalid parameter\n", fname) + ; + xprintf("Writing interior-point solution to '%s'...\n", fname); + fp = glp_open(fname, "w"), count = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* write comment lines */ + glp_format(fp, "c %-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name), count++; + glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; + glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; + glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; + switch (P->ipt_stat) + { case GLP_OPT: s = "OPTIMAL"; break; + case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break; + case GLP_NOFEAS: s = "INFEASIBLE (FINAL)"; break; + case GLP_UNDEF: s = "UNDEFINED"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s\n", "Status:", s), count++; + switch (P->dir) + { case GLP_MIN: s = "MINimum"; break; + case GLP_MAX: s = "MAXimum"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->ipt_obj, s), count++; + glp_format(fp, "c\n"), count++; + /* write solution line */ + glp_format(fp, "s ipt %d %d ", P->m, P->n), count++; + switch (P->ipt_stat) + { case GLP_OPT: glp_format(fp, "o"); break; + case GLP_INFEAS: glp_format(fp, "i"); break; + case GLP_NOFEAS: glp_format(fp, "n"); break; + case GLP_UNDEF: glp_format(fp, "u"); break; + default: glp_format(fp, "?"); break; + } + glp_format(fp, " %.*g\n", DBL_DIG, P->ipt_obj); + /* write row solution descriptor lines */ + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + glp_format(fp, "i %d %.*g %.*g\n", i, DBL_DIG, row->pval, + DBL_DIG, row->dval), count++; + } + /* write column solution descriptor lines */ + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + glp_format(fp, "j %d %.*g %.*g\n", j, DBL_DIG, col->pval, + DBL_DIG, col->dval), count++; + } + /* write end line */ + glp_format(fp, "e o f\n"), count++; + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* interior-point solution has been successfully written */ + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) + glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmaxf.c b/glpk-5.0/src/api/wrmaxf.c new file mode 100644 index 0000000..783cfaa --- /dev/null +++ b/glpk-5.0/src/api/wrmaxf.c @@ -0,0 +1,102 @@ +/* wrmaxf.c (write maximum flow problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_write_maxflow - write maximum flow problem data in DIMACS format +* +* SYNOPSIS +* +* int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, +* const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_maxflow writes maximum flow problem data in +* DIMACS format to a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_maxflow(glp_graph *G, int s, int t, int a_cap, + const char *fname) +{ glp_file *fp; + glp_vertex *v; + glp_arc *a; + int i, count = 0, ret; + double cap; + if (!(1 <= s && s <= G->nv)) + xerror("glp_write_maxflow: s = %d; source node number out of r" + "ange\n", s); + if (!(1 <= t && t <= G->nv)) + xerror("glp_write_maxflow: t = %d: sink node number out of ran" + "ge\n", t); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_write_mincost: a_cap = %d; invalid offset\n", + a_cap); + xprintf("Writing maximum flow problem data to '%s'...\n", + fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "c %s\n", + G->name == NULL ? "unknown" : G->name), count++; + xfprintf(fp, "p max %d %d\n", G->nv, G->na), count++; + xfprintf(fp, "n %d s\n", s), count++; + xfprintf(fp, "n %d t\n", t), count++; + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { if (a_cap >= 0) + memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); + else + cap = 1.0; + xfprintf(fp, "a %d %d %.*g\n", + a->tail->i, a->head->i, DBL_DIG, cap), count++; + } + } + xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmcf.c b/glpk-5.0/src/api/wrmcf.c new file mode 100644 index 0000000..234bc05 --- /dev/null +++ b/glpk-5.0/src/api/wrmcf.c @@ -0,0 +1,120 @@ +/* wrmcf.c (write min-cost flow problem data in DIMACS format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2009-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "glpk.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_write_mincost - write min-cost flow probl. data in DIMACS format +* +* SYNOPSIS +* +* int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, +* int a_cost, const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_mincost writes minimum cost flow problem data +* in DIMACS format to a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_mincost(glp_graph *G, int v_rhs, int a_low, int a_cap, + int a_cost, const char *fname) +{ glp_file *fp; + glp_vertex *v; + glp_arc *a; + int i, count = 0, ret; + double rhs, low, cap, cost; + if (v_rhs >= 0 && v_rhs > G->v_size - (int)sizeof(double)) + xerror("glp_write_mincost: v_rhs = %d; invalid offset\n", + v_rhs); + if (a_low >= 0 && a_low > G->a_size - (int)sizeof(double)) + xerror("glp_write_mincost: a_low = %d; invalid offset\n", + a_low); + if (a_cap >= 0 && a_cap > G->a_size - (int)sizeof(double)) + xerror("glp_write_mincost: a_cap = %d; invalid offset\n", + a_cap); + if (a_cost >= 0 && a_cost > G->a_size - (int)sizeof(double)) + xerror("glp_write_mincost: a_cost = %d; invalid offset\n", + a_cost); + xprintf("Writing min-cost flow problem data to '%s'...\n", + fname); + fp = glp_open(fname, "w"); + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xfprintf(fp, "c %s\n", + G->name == NULL ? "unknown" : G->name), count++; + xfprintf(fp, "p min %d %d\n", G->nv, G->na), count++; + if (v_rhs >= 0) + { for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + memcpy(&rhs, (char *)v->data + v_rhs, sizeof(double)); + if (rhs != 0.0) + xfprintf(fp, "n %d %.*g\n", i, DBL_DIG, rhs), count++; + } + } + for (i = 1; i <= G->nv; i++) + { v = G->v[i]; + for (a = v->out; a != NULL; a = a->t_next) + { if (a_low >= 0) + memcpy(&low, (char *)a->data + a_low, sizeof(double)); + else + low = 0.0; + if (a_cap >= 0) + memcpy(&cap, (char *)a->data + a_cap, sizeof(double)); + else + cap = 1.0; + if (a_cost >= 0) + memcpy(&cost, (char *)a->data + a_cost, sizeof(double)); + else + cost = 0.0; + xfprintf(fp, "a %d %d %.*g %.*g %.*g\n", + a->tail->i, a->head->i, DBL_DIG, low, DBL_DIG, cap, + DBL_DIG, cost), count++; + } + } + xfprintf(fp, "c eof\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrmip.c b/glpk-5.0/src/api/wrmip.c new file mode 100644 index 0000000..4ae36db --- /dev/null +++ b/glpk-5.0/src/api/wrmip.c @@ -0,0 +1,120 @@ +/* wrmip.c (write MIP solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_write_mip - write MIP solution in GLPK format +* +* SYNOPSIS +* +* int glp_write_mip(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_mip writes MIP solution to a text file in GLPK +* format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_mip(glp_prob *P, const char *fname) +{ glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, count, ret = 1; + char *s; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_write_mip: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_write_mip: fname = %d; invalid parameter\n", fname) + ; + xprintf("Writing MIP solution to '%s'...\n", fname); + fp = glp_open(fname, "w"), count = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* write comment lines */ + glp_format(fp, "c %-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name), count++; + glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; + glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; + glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; + switch (P->mip_stat) + { case GLP_OPT: s = "INTEGER OPTIMAL"; break; + case GLP_FEAS: s = "INTEGER NON-OPTIMAL"; break; + case GLP_NOFEAS: s = "INTEGER EMPTY"; break; + case GLP_UNDEF: s = "INTEGER UNDEFINED"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s\n", "Status:", s), count++; + switch (P->dir) + { case GLP_MIN: s = "MINimum"; break; + case GLP_MAX: s = "MAXimum"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->mip_obj, s), count++; + glp_format(fp, "c\n"), count++; + /* write solution line */ + glp_format(fp, "s mip %d %d ", P->m, P->n), count++; + switch (P->mip_stat) + { case GLP_OPT: glp_format(fp, "o"); break; + case GLP_FEAS: glp_format(fp, "f"); break; + case GLP_NOFEAS: glp_format(fp, "n"); break; + case GLP_UNDEF: glp_format(fp, "u"); break; + default: glp_format(fp, "?"); break; + } + glp_format(fp, " %.*g\n", DBL_DIG, P->mip_obj); + /* write row solution descriptor lines */ + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + glp_format(fp, "i %d %.*g\n", i, DBL_DIG, row->mipx), count++; + } + /* write column solution descriptor lines */ + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + glp_format(fp, "j %d %.*g\n", j, DBL_DIG, col->mipx), count++; + } + /* write end line */ + glp_format(fp, "e o f\n"), count++; + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* MIP solution has been successfully written */ + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) + glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrprob.c b/glpk-5.0/src/api/wrprob.c new file mode 100644 index 0000000..52f016a --- /dev/null +++ b/glpk-5.0/src/api/wrprob.c @@ -0,0 +1,164 @@ +/* wrprob.c (write problem data in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +#define xfprintf glp_format + +/*********************************************************************** +* NAME +* +* glp_write_prob - write problem data in GLPK format +* +* SYNOPSIS +* +* int glp_write_prob(glp_prob *P, int flags, const char *fname); +* +* The routine glp_write_prob writes problem data in GLPK LP/MIP format +* to a text file. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_prob(glp_prob *P, int flags, const char *fname) +{ glp_file *fp; + GLPROW *row; + GLPCOL *col; + GLPAIJ *aij; + int mip, i, j, count, ret; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_write_prob: P = %p; invalid problem object\n", + P); +#endif + if (flags != 0) + xerror("glp_write_prob: flags = %d; invalid parameter\n", + flags); + if (fname == NULL) + xerror("glp_write_prob: fname = %d; invalid parameter\n", + fname); + xprintf("Writing problem data to '%s'...\n", fname); + fp = glp_open(fname, "w"), count = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + /* write problem line */ + mip = (glp_get_num_int(P) > 0); + xfprintf(fp, "p %s %s %d %d %d\n", !mip ? "lp" : "mip", + P->dir == GLP_MIN ? "min" : P->dir == GLP_MAX ? "max" : "???", + P->m, P->n, P->nnz), count++; + if (P->name != NULL) + xfprintf(fp, "n p %s\n", P->name), count++; + if (P->obj != NULL) + xfprintf(fp, "n z %s\n", P->obj), count++; + /* write row descriptors */ + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + if (row->type == GLP_FX && row->lb == 0.0) + goto skip1; + xfprintf(fp, "i %d ", i), count++; + if (row->type == GLP_FR) + xfprintf(fp, "f\n"); + else if (row->type == GLP_LO) + xfprintf(fp, "l %.*g\n", DBL_DIG, row->lb); + else if (row->type == GLP_UP) + xfprintf(fp, "u %.*g\n", DBL_DIG, row->ub); + else if (row->type == GLP_DB) + xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, row->lb, DBL_DIG, + row->ub); + else if (row->type == GLP_FX) + xfprintf(fp, "s %.*g\n", DBL_DIG, row->lb); + else + xassert(row != row); +skip1: if (row->name != NULL) + xfprintf(fp, "n i %d %s\n", i, row->name), count++; + } + /* write column descriptors */ + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + if (!mip && col->type == GLP_LO && col->lb == 0.0) + goto skip2; + if (mip && col->kind == GLP_IV && col->type == GLP_DB && + col->lb == 0.0 && col->ub == 1.0) + goto skip2; + xfprintf(fp, "j %d ", j), count++; + if (mip) + { if (col->kind == GLP_CV) + xfprintf(fp, "c "); + else if (col->kind == GLP_IV) + xfprintf(fp, "i "); + else + xassert(col != col); + } + if (col->type == GLP_FR) + xfprintf(fp, "f\n"); + else if (col->type == GLP_LO) + xfprintf(fp, "l %.*g\n", DBL_DIG, col->lb); + else if (col->type == GLP_UP) + xfprintf(fp, "u %.*g\n", DBL_DIG, col->ub); + else if (col->type == GLP_DB) + xfprintf(fp, "d %.*g %.*g\n", DBL_DIG, col->lb, DBL_DIG, + col->ub); + else if (col->type == GLP_FX) + xfprintf(fp, "s %.*g\n", DBL_DIG, col->lb); + else + xassert(col != col); +skip2: if (col->name != NULL) + xfprintf(fp, "n j %d %s\n", j, col->name), count++; + } + /* write objective coefficient descriptors */ + if (P->c0 != 0.0) + xfprintf(fp, "a 0 0 %.*g\n", DBL_DIG, P->c0), count++; + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + if (col->coef != 0.0) + xfprintf(fp, "a 0 %d %.*g\n", j, DBL_DIG, col->coef), + count++; + } + /* write constraint coefficient descriptors */ + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + for (aij = row->ptr; aij != NULL; aij = aij->r_next) + xfprintf(fp, "a %d %d %.*g\n", i, aij->col->j, DBL_DIG, + aij->val), count++; + } + /* write end line */ + xfprintf(fp, "e o f\n"), count++; +#if 0 /* FIXME */ + xfflush(fp); +#endif + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + ret = 1; + goto done; + } + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) glp_close(fp); + return ret; +} + +/* eof */ diff --git a/glpk-5.0/src/api/wrsol.c b/glpk-5.0/src/api/wrsol.c new file mode 100644 index 0000000..85e7dd8 --- /dev/null +++ b/glpk-5.0/src/api/wrsol.c @@ -0,0 +1,172 @@ +/* wrsol.c (write basic solution in GLPK format) */ + +/*********************************************************************** +* This code is part of GLPK (GNU Linear Programming Kit). +* Copyright (C) 2010-2016 Free Software Foundation, Inc. +* Written by Andrew Makhorin <mao@gnu.org>. +* +* GLPK is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* GLPK is distributed in the hope that it will be useful, but WITHOUT +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +* License for more details. +* +* You should have received a copy of the GNU General Public License +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. +***********************************************************************/ + +#include "env.h" +#include "prob.h" + +/*********************************************************************** +* NAME +* +* glp_write_sol - write basic solution in GLPK format +* +* SYNOPSIS +* +* int glp_write_sol(glp_prob *P, const char *fname); +* +* DESCRIPTION +* +* The routine glp_write_sol writes basic solution to a text file in +* GLPK format. +* +* RETURNS +* +* If the operation was successful, the routine returns zero. Otherwise +* it prints an error message and returns non-zero. */ + +int glp_write_sol(glp_prob *P, const char *fname) +{ glp_file *fp; + GLPROW *row; + GLPCOL *col; + int i, j, count, ret = 1; + char *s; +#if 0 /* 04/IV-2016 */ + if (P == NULL || P->magic != GLP_PROB_MAGIC) + xerror("glp_write_sol: P = %p; invalid problem object\n", P); +#endif + if (fname == NULL) + xerror("glp_write_sol: fname = %d; invalid parameter\n", fname) + ; + xprintf("Writing basic solution to '%s'...\n", fname); + fp = glp_open(fname, "w"), count = 0; + if (fp == NULL) + { xprintf("Unable to create '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* write comment lines */ + glp_format(fp, "c %-12s%s\n", "Problem:", + P->name == NULL ? "" : P->name), count++; + glp_format(fp, "c %-12s%d\n", "Rows:", P->m), count++; + glp_format(fp, "c %-12s%d\n", "Columns:", P->n), count++; + glp_format(fp, "c %-12s%d\n", "Non-zeros:", P->nnz), count++; + switch (glp_get_status(P)) + { case GLP_OPT: s = "OPTIMAL"; break; + case GLP_FEAS: s = "FEASIBLE"; break; + case GLP_INFEAS: s = "INFEASIBLE (INTERMEDIATE)"; break; + case GLP_NOFEAS: s = "INFEASIBLE (FINAL)"; break; + case GLP_UNBND: s = "UNBOUNDED"; break; + case GLP_UNDEF: s = "UNDEFINED"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s\n", "Status:", s), count++; + switch (P->dir) + { case GLP_MIN: s = "MINimum"; break; + case GLP_MAX: s = "MAXimum"; break; + default: s = "???"; break; + } + glp_format(fp, "c %-12s%s%s%.10g (%s)\n", "Objective:", + P->obj == NULL ? "" : P->obj, + P->obj == NULL ? "" : " = ", P->obj_val, s), count++; + glp_format(fp, "c\n"), count++; + /* write solution line */ + glp_format(fp, "s bas %d %d ", P->m, P->n), count++; + switch (P->pbs_stat) + { case GLP_UNDEF: glp_format(fp, "u"); break; + case GLP_FEAS: glp_format(fp, "f"); break; + case GLP_INFEAS: glp_format(fp, "i"); break; + case GLP_NOFEAS: glp_format(fp, "n"); break; + default: glp_format(fp, "?"); break; + } + glp_format(fp, " "); + switch (P->dbs_stat) + { case GLP_UNDEF: glp_format(fp, "u"); break; + case GLP_FEAS: glp_format(fp, "f"); break; + case GLP_INFEAS: glp_format(fp, "i"); break; + case GLP_NOFEAS: glp_format(fp, "n"); break; + default: glp_format(fp, "?"); break; + } + glp_format(fp, " %.*g\n", DBL_DIG, P->obj_val); + /* write row solution descriptor lines */ + for (i = 1; i <= P->m; i++) + { row = P->row[i]; + glp_format(fp, "i %d ", i), count++; + switch (row->stat) + { case GLP_BS: + glp_format(fp, "b"); + break; + case GLP_NL: + glp_format(fp, "l"); + break; + case GLP_NU: + glp_format(fp, "u"); + break; + case GLP_NF: + glp_format(fp, "f"); + break; + case GLP_NS: + glp_format(fp, "s"); + break; + default: + xassert(row != row); + } + glp_format(fp, " %.*g %.*g\n", DBL_DIG, row->prim, DBL_DIG, + row->dual); + } + /* write column solution descriptor lines */ + for (j = 1; j <= P->n; j++) + { col = P->col[j]; + glp_format(fp, "j %d ", j), count++; + switch (col->stat) + { case GLP_BS: + glp_format(fp, "b"); + break; + case GLP_NL: + glp_format(fp, "l"); + break; + case GLP_NU: + glp_format(fp, "u"); + break; + case GLP_NF: + glp_format(fp, "f"); + break; + case GLP_NS: + glp_format(fp, "s"); + break; + default: + xassert(col != col); + } + glp_format(fp, " %.*g %.*g\n", DBL_DIG, col->prim, DBL_DIG, + col->dual); + } + /* write end line */ + glp_format(fp, "e o f\n"), count++; + if (glp_ioerr(fp)) + { xprintf("Write error on '%s' - %s\n", fname, get_err_msg()); + goto done; + } + /* basic solution has been successfully written */ + xprintf("%d lines were written\n", count); + ret = 0; +done: if (fp != NULL) + glp_close(fp); + return ret; +} + +/* eof */ |