Add graph references
This commit is contained in:
+153
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
+1281
File diff suppressed because it is too large
Load Diff
+183
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
+1450
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
+1586
File diff suppressed because it is too large
Load Diff
+489
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 */
|
||||
Reference in New Issue
Block a user