Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
+153
View File
@@ -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 */
+161
View File
@@ -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 */
+102
View File
@@ -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 */
+152
View File
@@ -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 */
+76
View File
@@ -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 */
+80
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+183
View File
@@ -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 */
+267
View File
@@ -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 */
+502
View File
@@ -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 */
+20
View File
@@ -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 */
+265
View File
@@ -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 */
+128
View File
@@ -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 */
+112
View File
@@ -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 */
+112
View File
@@ -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 */
+219
View File
@@ -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 */
+249
View File
@@ -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 */
+159
View File
@@ -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 */
+267
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+20
View File
@@ -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 */
+141
View File
@@ -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 */
+184
View File
@@ -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 */
+153
View File
@@ -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 */
+284
View File
@@ -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 */
File diff suppressed because it is too large Load Diff
+489
View File
@@ -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 */
+164
View File
@@ -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 */
+154
View File
@@ -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 */
+166
View File
@@ -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 */
+300
View File
@@ -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 */
+200
View File
@@ -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 */
+162
View File
@@ -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 */
+160
View File
@@ -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 */
+134
View File
@@ -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 */
+183
View File
@@ -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 */
+161
View File
@@ -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 */
+184
View File
@@ -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 */
+170
View File
@@ -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 */
+375
View File
@@ -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 */
+223
View File
@@ -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 */
+20
View File
@@ -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 */
+108
View File
@@ -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 */
+121
View File
@@ -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 */
+120
View File
@@ -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 */
+148
View File
@@ -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 */
+105
View File
@@ -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 */
+100
View File
@@ -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 */
+85
View File
@@ -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 */
+122
View File
@@ -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 */
+102
View File
@@ -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 */
+120
View File
@@ -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 */
+120
View File
@@ -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 */
+164
View File
@@ -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 */
+172
View File
@@ -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 */