Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
/* simplex.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SIMPLEX_H
#define SIMPLEX_H
#include "prob.h"
#define spx_primal _glp_spx_primal
int spx_primal(glp_prob *P, const glp_smcp *parm);
/* driver to the primal simplex method */
#define spy_dual _glp_spy_dual
int spy_dual(glp_prob *P, const glp_smcp *parm);
/* driver to the dual simplex method */
#endif
/* eof */
+263
View File
@@ -0,0 +1,263 @@
/* spxat.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spxat.h"
/***********************************************************************
* spx_alloc_at - allocate constraint matrix in sparse row-wise format
*
* This routine allocates the memory for arrays needed to represent the
* constraint matrix in sparse row-wise format. */
void spx_alloc_at(SPXLP *lp, SPXAT *at)
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
at->ptr = talloc(1+m+1, int);
at->ind = talloc(1+nnz, int);
at->val = talloc(1+nnz, double);
at->work = talloc(1+n, double);
return;
}
/***********************************************************************
* spx_build_at - build constraint matrix in sparse row-wise format
*
* This routine builds sparse row-wise representation of the constraint
* matrix A using its sparse column-wise representation stored in the
* lp object, and stores the result in the at object. */
void spx_build_at(SPXLP *lp, SPXAT *at)
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int *AT_ptr = at->ptr;
int *AT_ind = at->ind;
double *AT_val = at->val;
int i, k, ptr, end, pos;
/* calculate AT_ptr[i] = number of non-zeros in i-th row */
memset(&AT_ptr[1], 0, m * sizeof(int));
for (k = 1; k <= n; k++)
{ ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
AT_ptr[A_ind[ptr]]++;
}
/* set AT_ptr[i] to position after last element in i-th row */
AT_ptr[1]++;
for (i = 2; i <= m; i++)
AT_ptr[i] += AT_ptr[i-1];
xassert(AT_ptr[m] == nnz+1);
AT_ptr[m+1] = nnz+1;
/* build row-wise representation and re-arrange AT_ptr[i] */
for (k = n; k >= 1; k--)
{ /* copy elements from k-th column to corresponding rows */
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
{ pos = --AT_ptr[A_ind[ptr]];
AT_ind[pos] = k;
AT_val[pos] = A_val[ptr];
}
}
xassert(AT_ptr[1] == 1);
return;
}
/***********************************************************************
* spx_at_prod - compute product y := y + s * A'* x
*
* This routine computes the product:
*
* y := y + s * A'* x,
*
* where A' is a matrix transposed to the mxn-matrix A of constraint
* coefficients, x is a m-vector, s is a scalar, y is a n-vector.
*
* The routine uses the row-wise representation of the matrix A and
* computes the product as a linear combination:
*
* y := y + s * (A'[1] * x[1] + ... + A'[m] * x[m]),
*
* where A'[i] is i-th row of A, 1 <= i <= m. */
void spx_at_prod(SPXLP *lp, SPXAT *at, double y[/*1+n*/], double s,
const double x[/*1+m*/])
{ int m = lp->m;
int *AT_ptr = at->ptr;
int *AT_ind = at->ind;
double *AT_val = at->val;
int i, ptr, end;
double t;
for (i = 1; i <= m; i++)
{ if (x[i] != 0.0)
{ /* y := y + s * (i-th row of A) * x[i] */
t = s * x[i];
ptr = AT_ptr[i];
end = AT_ptr[i+1];
for (; ptr < end; ptr++)
y[AT_ind[ptr]] += AT_val[ptr] * t;
}
}
return;
}
/***********************************************************************
* spx_nt_prod1 - compute product y := y + s * N'* x
*
* This routine computes the product:
*
* y := y + s * N'* x,
*
* where N' is a matrix transposed to the mx(n-m)-matrix N composed
* from non-basic columns of the constraint matrix A, x is a m-vector,
* s is a scalar, y is (n-m)-vector.
*
* If the flag ign is non-zero, the routine ignores the input content
* of the array y assuming that y = 0. */
void spx_nt_prod1(SPXLP *lp, SPXAT *at, double y[/*1+n-m*/], int ign,
double s, const double x[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
double *work = at->work;
int j, k;
for (k = 1; k <= n; k++)
work[k] = 0.0;
if (!ign)
{ for (j = 1; j <= n-m; j++)
work[head[m+j]] = y[j];
}
spx_at_prod(lp, at, work, s, x);
for (j = 1; j <= n-m; j++)
y[j] = work[head[m+j]];
return;
}
/***********************************************************************
* spx_eval_trow1 - compute i-th row of simplex table
*
* This routine computes i-th row of the current simplex table
* T = (T[i,j]) = - inv(B) * N, 1 <= i <= m, using representation of
* the constraint matrix A in row-wise format.
*
* The vector rho = (rho[j]), which is i-th row of the basis inverse
* inv(B), should be previously computed with the routine spx_eval_rho.
* It is assumed that elements of this vector are stored in the array
* locations rho[1], ..., rho[m].
*
* There exist two ways to compute the simplex table row.
*
* 1. T[i,j], j = 1,...,n-m, is computed as inner product:
*
* m
* T[i,j] = - sum a[i,k] * rho[i],
* i=1
*
* where N[j] = A[k] is a column of the constraint matrix corresponding
* to non-basic variable xN[j]. The estimated number of operations in
* this case is:
*
* n1 = (n - m) * (nnz(A) / n),
*
* (n - m) is the number of columns of N, nnz(A) / n is the average
* number of non-zeros in one column of A and, therefore, of N.
*
* 2. The simplex table row is computed as part of a linear combination
* of rows of A with coefficients rho[i] != 0. The estimated number
* of operations in this case is:
*
* n2 = nnz(rho) * (nnz(A) / m),
*
* where nnz(rho) is the number of non-zeros in the vector rho,
* nnz(A) / m is the average number of non-zeros in one row of A.
*
* If n1 < n2, the routine computes the simples table row using the
* first way (like the routine spx_eval_trow). Otherwise, the routine
* uses the second way calling the routine spx_nt_prod1.
*
* On exit components of the simplex table row are stored in the array
* locations trow[1], ... trow[n-m]. */
void spx_eval_trow1(SPXLP *lp, SPXAT *at, const double rho[/*1+m*/],
double trow[/*1+n-m*/])
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
int i, j, nnz_rho;
double cnt1, cnt2;
/* determine nnz(rho) */
nnz_rho = 0;
for (i = 1; i <= m; i++)
{ if (rho[i] != 0.0)
nnz_rho++;
}
/* estimate the number of operations for both ways */
cnt1 = (double)(n - m) * ((double)nnz / (double)n);
cnt2 = (double)nnz_rho * ((double)nnz / (double)m);
/* compute i-th row of simplex table */
if (cnt1 < cnt2)
{ /* as inner products */
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int *head = lp->head;
int k, ptr, end;
double tij;
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* compute t[i,j] = - N'[j] * pi */
tij = 0.0;
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
tij -= A_val[ptr] * rho[A_ind[ptr]];
trow[j] = tij;
}
}
else
{ /* as linear combination */
spx_nt_prod1(lp, at, trow, 1, -1.0, rho);
}
return;
}
/***********************************************************************
* spx_free_at - deallocate constraint matrix in sparse row-wise format
*
* This routine deallocates the memory used for arrays of the program
* object at. */
void spx_free_at(SPXLP *lp, SPXAT *at)
{ xassert(lp == lp);
tfree(at->ptr);
tfree(at->ind);
tfree(at->val);
tfree(at->work);
return;
}
/* eof */
+78
View File
@@ -0,0 +1,78 @@
/* spxat.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPXAT_H
#define SPXAT_H
#include "spxlp.h"
typedef struct SPXAT SPXAT;
struct SPXAT
{ /* mxn-matrix A of constraint coefficients in sparse row-wise
* format */
int *ptr; /* int ptr[1+m+1]; */
/* ptr[0] is not used;
* ptr[i], 1 <= i <= m, is starting position of i-th row in
* arrays ind and val; note that ptr[1] is always 1;
* ptr[m+1] indicates the position after the last element in
* arrays ind and val, i.e. ptr[m+1] = nnz+1, where nnz is the
* number of non-zero elements in matrix A;
* the length of i-th row (the number of non-zero elements in
* that row) can be calculated as ptr[i+1] - ptr[i] */
int *ind; /* int ind[1+nnz]; */
/* column indices */
double *val; /* double val[1+nnz]; */
/* non-zero element values */
double *work; /* double work[1+n]; */
/* working array */
};
#define spx_alloc_at _glp_spx_alloc_at
void spx_alloc_at(SPXLP *lp, SPXAT *at);
/* allocate constraint matrix in sparse row-wise format */
#define spx_build_at _glp_spx_build_at
void spx_build_at(SPXLP *lp, SPXAT *at);
/* build constraint matrix in sparse row-wise format */
#define spx_at_prod _glp_spx_at_prod
void spx_at_prod(SPXLP *lp, SPXAT *at, double y[/*1+n*/], double s,
const double x[/*1+m*/]);
/* compute product y := y + s * A'* x */
#define spx_nt_prod1 _glp_spx_nt_prod1
void spx_nt_prod1(SPXLP *lp, SPXAT *at, double y[/*1+n-m*/], int ign,
double s, const double x[/*1+m*/]);
/* compute product y := y + s * N'* x */
#define spx_eval_trow1 _glp_spx_eval_trow1
void spx_eval_trow1(SPXLP *lp, SPXAT *at, const double rho[/*1+m*/],
double trow[/*1+n-m*/]);
/* compute i-th row of simplex table */
#define spx_free_at _glp_spx_free_at
void spx_free_at(SPXLP *lp, SPXAT *at);
/* deallocate constraint matrix in sparse row-wise format */
#endif
/* eof */
+379
View File
@@ -0,0 +1,379 @@
/* spxchuzc.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spxchuzc.h"
/***********************************************************************
* spx_chuzc_sel - select eligible non-basic variables
*
* This routine selects eligible non-basic variables xN[j], whose
* reduced costs d[j] have "wrong" sign, i.e. changing such xN[j] in
* feasible direction improves (decreases) the objective function.
*
* Reduced costs of non-basic variables should be placed in the array
* locations d[1], ..., d[n-m].
*
* Non-basic variable xN[j] is considered eligible if:
*
* d[j] <= -eps[j] and xN[j] can increase
*
* d[j] >= +eps[j] and xN[j] can decrease
*
* for
*
* eps[j] = tol + tol1 * |cN[j]|,
*
* where cN[j] is the objective coefficient at xN[j], tol and tol1 are
* specified tolerances.
*
* On exit the routine stores indices j of eligible non-basic variables
* xN[j] to the array locations list[1], ..., list[num] and returns the
* number of such variables 0 <= num <= n-m. (If the parameter list is
* specified as NULL, no indices are stored.) */
int spx_chuzc_sel(SPXLP *lp, const double d[/*1+n-m*/], double tol,
double tol1, int list[/*1+n-m*/])
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, k, num;
double ck, eps;
num = 0;
/* walk thru list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
if (l[k] == u[k])
{ /* xN[j] is fixed variable; skip it */
continue;
}
/* determine absolute tolerance eps[j] */
ck = c[k];
eps = tol + tol1 * (ck >= 0.0 ? +ck : -ck);
/* check if xN[j] is eligible */
if (d[j] <= -eps)
{ /* xN[j] should be able to increase */
if (flag[j])
{ /* but its upper bound is active */
continue;
}
}
else if (d[j] >= +eps)
{ /* xN[j] should be able to decrease */
if (!flag[j] && l[k] != -DBL_MAX)
{ /* but its lower bound is active */
continue;
}
}
else /* -eps < d[j] < +eps */
{ /* xN[j] does not affect the objective function within the
* specified tolerance */
continue;
}
/* xN[j] is eligible non-basic variable */
num++;
if (list != NULL)
list[num] = j;
}
return num;
}
/***********************************************************************
* spx_chuzc_std - choose non-basic variable (Dantzig's rule)
*
* This routine chooses most eligible non-basic variable xN[q]
* according to Dantzig's ("standard") rule:
*
* d[q] = max |d[j]|,
* j in J
*
* where J <= {1, ..., n-m} is the set of indices of eligible non-basic
* variables, d[j] is the reduced cost of non-basic variable xN[j] in
* the current basis.
*
* Reduced costs of non-basic variables should be placed in the array
* locations d[1], ..., d[n-m].
*
* Indices of eligible non-basic variables j in J should be placed in
* the array locations list[1], ..., list[num], where num = |J| > 0 is
* the total number of such variables.
*
* On exit the routine returns q, the index of the non-basic variable
* xN[q] chosen. */
int spx_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/], int num,
const int list[])
{ int m = lp->m;
int n = lp->n;
int j, q, t;
double abs_dj, abs_dq;
xassert(0 < num && num <= n-m);
q = 0, abs_dq = -1.0;
for (t = 1; t <= num; t++)
{ j = list[t];
abs_dj = (d[j] >= 0.0 ? +d[j] : -d[j]);
if (abs_dq < abs_dj)
q = j, abs_dq = abs_dj;
}
xassert(q != 0);
return q;
}
/***********************************************************************
* spx_alloc_se - allocate pricing data block
*
* This routine allocates the memory for arrays used in the pricing
* data block. */
void spx_alloc_se(SPXLP *lp, SPXSE *se)
{ int m = lp->m;
int n = lp->n;
se->valid = 0;
se->refsp = talloc(1+n, char);
se->gamma = talloc(1+n-m, double);
se->work = talloc(1+m, double);
return;
}
/***********************************************************************
* spx_reset_refsp - reset reference space
*
* This routine resets (re-initializes) the reference space composing
* it from variables which are non-basic in the current basis, and sets
* all weights gamma[j] to 1. */
void spx_reset_refsp(SPXLP *lp, SPXSE *se)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *gamma = se->gamma;
int j, k;
se->valid = 1;
memset(&refsp[1], 0, n * sizeof(char));
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
refsp[k] = 1;
gamma[j] = 1.0;
}
return;
}
/***********************************************************************
* spx_eval_gamma_j - compute projected steepest edge weight directly
*
* This routine computes projected steepest edge weight gamma[j],
* 1 <= j <= n-m, for the current basis directly with the formula:
*
* m
* gamma[j] = delta[j] + sum eta[i] * T[i,j]**2,
* i=1
*
* where T[i,j] is element of the current simplex table, and
*
* ( 1, if xB[i] is in the reference space
* eta[i] = {
* ( 0, otherwise
*
* ( 1, if xN[j] is in the reference space
* delta[j] = {
* ( 0, otherwise
*
* NOTE: For testing/debugging only. */
double spx_eval_gamma_j(SPXLP *lp, SPXSE *se, int j)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *tcol = se->work;
int i, k;
double gamma_j;
xassert(se->valid);
xassert(1 <= j && j <= n-m);
k = head[m+j]; /* x[k] = xN[j] */
gamma_j = (refsp[k] ? 1.0 : 0.0);
spx_eval_tcol(lp, j, tcol);
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
if (refsp[k])
gamma_j += tcol[i] * tcol[i];
}
return gamma_j;
}
/***********************************************************************
* spx_chuzc_pse - choose non-basic variable (projected steepest edge)
*
* This routine chooses most eligible non-basic variable xN[q]
* according to the projected steepest edge method:
*
* d[q]**2 d[j]**2
* -------- = max -------- ,
* gamma[q] j in J gamma[j]
*
* where J <= {1, ..., n-m} is the set of indices of eligible non-basic
* variable, d[j] is the reduced cost of non-basic variable xN[j] in
* the current basis, gamma[j] is the projected steepest edge weight.
*
* Reduced costs of non-basic variables should be placed in the array
* locations d[1], ..., d[n-m].
*
* Indices of eligible non-basic variables j in J should be placed in
* the array locations list[1], ..., list[num], where num = |J| > 0 is
* the total number of such variables.
*
* On exit the routine returns q, the index of the non-basic variable
* xN[q] chosen. */
int spx_chuzc_pse(SPXLP *lp, SPXSE *se, const double d[/*1+n-m*/],
int num, const int list[])
{ int m = lp->m;
int n = lp->n;
double *gamma = se->gamma;
int j, q, t;
double best, temp;
xassert(se->valid);
xassert(0 < num && num <= n-m);
q = 0, best = -1.0;
for (t = 1; t <= num; t++)
{ j = list[t];
/* FIXME */
if (gamma[j] < DBL_EPSILON)
temp = 0.0;
else
temp = (d[j] * d[j]) / gamma[j];
if (best < temp)
q = j, best = temp;
}
xassert(q != 0);
return q;
}
/***********************************************************************
* spx_update_gamma - update projected steepest edge weights exactly
*
* This routine updates the vector gamma = (gamma[j]) of projected
* steepest edge weights exactly, for the adjacent basis.
*
* On entry to the routine the content of the se object should be valid
* and should correspond to the current basis.
*
* The parameter 1 <= p <= m specifies basic variable xB[p] which
* becomes non-basic variable xN[q] in the adjacent basis.
*
* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
* becomes basic variable xB[p] in the adjacent basis.
*
* It is assumed that the array trow contains elements of p-th (pivot)
* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
* It is also assumed that the array tcol contains elements of q-th
* (pivot) column T[q] of the simple table in locations tcol[1], ...,
* tcol[m]. (These row and column should be computed for the current
* basis.)
*
* For details about the formulae used see the program documentation.
*
* The routine also computes the relative error:
*
* e = |gamma[q] - gamma'[q]| / (1 + |gamma[q]|),
*
* where gamma'[q] is the weight for xN[q] on entry to the routine,
* and returns e on exit. (If e happens to be large enough, the calling
* program may reset the reference space, since other weights also may
* be inaccurate.) */
double spx_update_gamma(SPXLP *lp, SPXSE *se, int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *gamma = se->gamma;
double *u = se->work;
int i, j, k, ptr, end;
double gamma_q, delta_q, e, r, s, t1, t2;
xassert(se->valid);
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* compute gamma[q] in current basis more accurately; also
* compute auxiliary vector u */
k = head[m+q]; /* x[k] = xN[q] */
gamma_q = delta_q = (refsp[k] ? 1.0 : 0.0);
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
if (refsp[k])
{ gamma_q += tcol[i] * tcol[i];
u[i] = tcol[i];
}
else
u[i] = 0.0;
}
bfd_btran(lp->bfd, u);
/* compute relative error in gamma[q] */
e = fabs(gamma_q - gamma[q]) / (1.0 + gamma_q);
/* compute new gamma[q] */
gamma[q] = gamma_q / (tcol[p] * tcol[p]);
/* compute new gamma[j] for all j != q */
for (j = 1; j <= n-m; j++)
{ if (j == q)
continue;
if (-1e-9 < trow[j] && trow[j] < +1e-9)
{ /* T[p,j] is close to zero; gamma[j] is not changed */
continue;
}
/* compute r[j] = T[p,j] / T[p,q] */
r = trow[j] / tcol[p];
/* compute inner product s[j] = N'[j] * u, where N[j] = A[k]
* is constraint matrix column corresponding to xN[j] */
s = 0.0;
k = head[m+j]; /* x[k] = xN[j] */
ptr = lp->A_ptr[k];
end = lp->A_ptr[k+1];
for (; ptr < end; ptr++)
s += lp->A_val[ptr] * u[lp->A_ind[ptr]];
/* compute new gamma[j] */
t1 = gamma[j] + r * (r * gamma_q + s + s);
t2 = (refsp[k] ? 1.0 : 0.0) + delta_q * r * r;
gamma[j] = (t1 >= t2 ? t1 : t2);
}
return e;
}
/***********************************************************************
* spx_free_se - deallocate pricing data block
*
* This routine deallocates the memory used for arrays in the pricing
* data block. */
void spx_free_se(SPXLP *lp, SPXSE *se)
{ xassert(lp == lp);
tfree(se->refsp);
tfree(se->gamma);
tfree(se->work);
return;
}
/* eof */
+83
View File
@@ -0,0 +1,83 @@
/* spxchuzc.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPXCHUZC_H
#define SPXCHUZC_H
#include "spxlp.h"
#define spx_chuzc_sel _glp_spx_chuzc_sel
int spx_chuzc_sel(SPXLP *lp, const double d[/*1+n-m*/], double tol,
double tol1, int list[/*1+n-m*/]);
/* select eligible non-basic variables */
#define spx_chuzc_std _glp_spx_chuzc_std
int spx_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/], int num,
const int list[]);
/* choose non-basic variable (Dantzig's rule) */
typedef struct SPXSE SPXSE;
struct SPXSE
{ /* projected steepest edge and Devex pricing data block */
int valid;
/* content validity flag */
char *refsp; /* char refsp[1+n]; */
/* refsp[0] is not used;
* refsp[k], 1 <= k <= n, is the flag meaning that variable x[k]
* is in the reference space */
double *gamma; /* double gamma[1+n-m]; */
/* gamma[0] is not used;
* gamma[j], 1 <= j <= n-m, is the weight for reduced cost d[j]
* of non-basic variable xN[j] in the current basis */
double *work; /* double work[1+m]; */
/* working array */
};
#define spx_alloc_se _glp_spx_alloc_se
void spx_alloc_se(SPXLP *lp, SPXSE *se);
/* allocate pricing data block */
#define spx_reset_refsp _glp_spx_reset_refsp
void spx_reset_refsp(SPXLP *lp, SPXSE *se);
/* reset reference space */
#define spx_eval_gamma_j _glp_spx_eval_gamma_j
double spx_eval_gamma_j(SPXLP *lp, SPXSE *se, int j);
/* compute projeted steepest edge weight directly */
#define spx_chuzc_pse _glp_spx_chuzc_pse
int spx_chuzc_pse(SPXLP *lp, SPXSE *se, const double d[/*1+n-m*/],
int num, const int list[]);
/* choose non-basic variable (projected steepest edge) */
#define spx_update_gamma _glp_spx_update_gamma
double spx_update_gamma(SPXLP *lp, SPXSE *se, int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
/* update projected steepest edge weights exactly */
#define spx_free_se _glp_spx_free_se
void spx_free_se(SPXLP *lp, SPXSE *se);
/* deallocate pricing data block */
#endif
/* eof */
+592
View File
@@ -0,0 +1,592 @@
/* spxchuzr.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015-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 "spxchuzr.h"
/***********************************************************************
* spx_chuzr_std - choose basic variable (textbook ratio test)
*
* This routine implements an improved textbook ratio test to choose
* basic variable xB[p].
*
* The parameter phase specifies the search phase:
*
* 1 - searching for feasible basic solution. In this case the routine
* uses artificial bounds of basic variables that correspond to
* breakpoints of the penalty function:
*
* ( lB[i], if cB[i] = 0
* (
* lB'[i] = { uB[i], if cB[i] > 0
* (
* ( -inf, if cB[i] < 0
*
* ( uB[i], if cB[i] = 0
* (
* uB'[i] = { +inf, if cB[i] > 0
* (
* ( lB[i], if cB[i] < 0
*
* where lB[i] and uB[i] are original bounds of variable xB[i],
* cB[i] is the penalty (objective) coefficient of that variable.
*
* 2 - searching for optimal basic solution. In this case the routine
* uses original bounds of basic variables.
*
* Current values of basic variables should be placed in the array
* locations beta[1], ..., beta[m].
*
* The parameter 1 <= q <= n-m specifies the index of non-basic
* variable xN[q] chosen.
*
* The parameter s specifies the direction in which xN[q] changes:
* s = +1.0 means xN[q] increases, and s = -1.0 means xN[q] decreases.
* (Thus, the corresponding ray parameter is theta = s (xN[q] - f[q]),
* where f[q] is the active bound of xN[q] in the current basis.)
*
* Elements of q-th simplex table column T[q] = (t[i,q]) corresponding
* to non-basic variable xN[q] should be placed in the array locations
* tcol[1], ..., tcol[m].
*
* The parameter tol_piv specifies a tolerance for elements of the
* simplex table column T[q]. If |t[i,q]| < tol_piv, basic variable
* xB[i] is skipped, i.e. it is assumed that it does not depend on the
* ray parameter theta.
*
* The parameters tol and tol1 specify tolerances used to increase the
* choice freedom by simulating an artificial degeneracy as follows.
* If beta[i] <= lB[i] + delta[i], where delta[i] = tol + tol1 |lB[i]|,
* it is assumed that beta[i] is exactly the same as lB[i]. Similarly,
* if beta[i] >= uB[i] - delta[i], where delta[i] = tol + tol1 |uB[i]|,
* it is assumed that beta[i] is exactly the same as uB[i].
*
* The routine determines the index 1 <= p <= m of basic variable xB[p]
* that reaches its (lower or upper) bound first on increasing the ray
* parameter theta, stores the bound flag (0 - lower bound or fixed
* value, 1 - upper bound) to the location pointed to by the pointer
* p_flag, and returns the index p. If non-basic variable xN[q] is
* double-bounded and reaches its opposite bound first, the routine
* returns (-1). And if the ray parameter may increase unlimitedly, the
* routine returns zero.
*
* Should note that the bound flag stored to the location pointed to by
* p_flag corresponds to the original (not artficial) bound of variable
* xB[p] and defines the active bound flag lp->flag[q] to be set in the
* adjacent basis for that basic variable. */
int spx_chuzr_std(SPXLP *lp, int phase, const double beta[/*1+m*/],
int q, double s, const double tcol[/*1+m*/], int *p_flag,
double tol_piv, double tol, double tol1)
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int i, i_flag, k, p;
double alfa, biga, delta, lk, uk, teta, teta_min;
xassert(phase == 1 || phase == 2);
xassert(1 <= q && q <= n-m);
xassert(s == +1.0 || s == -1.0);
/* determine initial teta_min */
k = head[m+q]; /* x[k] = xN[q] */
if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
{ /* xN[q] has no opposite bound */
p = 0, *p_flag = 0, teta_min = DBL_MAX, biga = 0.0;
}
else
{ /* xN[q] have both lower and upper bounds */
p = -1, *p_flag = 0, teta_min = fabs(l[k] - u[k]), biga = 1.0;
}
/* walk thru the list of basic variables */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
/* determine alfa such that delta xB[i] = alfa * teta */
alfa = s * tcol[i];
if (alfa <= -tol_piv)
{ /* xB[i] decreases */
/* determine actual lower bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* xB[i] has no actual lower bound */
continue;
}
else if (phase == 1 && c[k] > 0.0)
{ /* actual lower bound of xB[i] is its upper bound */
lk = u[k];
xassert(lk != +DBL_MAX);
i_flag = 1;
}
else
{ /* actual lower bound of xB[i] is its original bound */
lk = l[k];
if (lk == -DBL_MAX)
continue;
i_flag = 0;
}
/* determine teta on which xB[i] reaches its lower bound */
delta = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
if (beta[i] <= lk + delta)
teta = 0.0;
else
teta = (lk - beta[i]) / alfa;
}
else if (alfa >= +tol_piv)
{ /* xB[i] increases */
/* determine actual upper bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* actual upper bound of xB[i] is its lower bound */
uk = l[k];
xassert(uk != -DBL_MAX);
i_flag = 0;
}
else if (phase == 1 && c[k] > 0.0)
{ /* xB[i] has no actual upper bound */
continue;
}
else
{ /* actual upper bound of xB[i] is its original bound */
uk = u[k];
if (uk == +DBL_MAX)
continue;
i_flag = 1;
}
/* determine teta on which xB[i] reaches its upper bound */
delta = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
if (beta[i] >= uk - delta)
teta = 0.0;
else
teta = (uk - beta[i]) / alfa;
}
else
{ /* xB[i] does not depend on teta */
continue;
}
/* choose basic variable xB[p] for which teta is minimal */
xassert(teta >= 0.0);
alfa = (alfa >= 0.0 ? +alfa : -alfa);
if (teta_min > teta || (teta_min == teta && biga < alfa))
p = i, *p_flag = i_flag, teta_min = teta, biga = alfa;
}
/* if xB[p] is fixed variable, adjust its bound flag */
if (p > 0)
{ k = head[p];
if (l[k] == u[k])
*p_flag = 0;
}
return p;
}
/***********************************************************************
* spx_chuzr_harris - choose basic variable (Harris' ratio test)
*
* This routine implements Harris' ratio test to choose basic variable
* xB[p].
*
* All the parameters, except tol and tol1, as well as the returned
* value have the same meaning as for the routine spx_chuzr_std (see
* above).
*
* The parameters tol and tol1 specify tolerances on bound violations
* for basic variables. For the lower bound of basic variable xB[i] the
* tolerance is delta[i] = tol + tol1 |lB[i]|, and for the upper bound
* the tolerance is delta[i] = tol + tol1 |uB[i]|. */
int spx_chuzr_harris(SPXLP *lp, int phase, const double beta[/*1+m*/],
int q, double s, const double tcol[/*1+m*/], int *p_flag,
double tol_piv, double tol, double tol1)
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int i, i_flag, k, p;
double alfa, biga, delta, lk, uk, teta, teta_min;
xassert(phase == 1 || phase == 2);
xassert(1 <= q && q <= n-m);
xassert(s == +1.0 || s == -1.0);
/*--------------------------------------------------------------*/
/* first pass: determine teta_min for relaxed bounds */
/*--------------------------------------------------------------*/
teta_min = DBL_MAX;
/* walk thru the list of basic variables */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
/* determine alfa such that delta xB[i] = alfa * teta */
alfa = s * tcol[i];
if (alfa <= -tol_piv)
{ /* xB[i] decreases */
/* determine actual lower bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* xB[i] has no actual lower bound */
continue;
}
else if (phase == 1 && c[k] > 0.0)
{ /* actual lower bound of xB[i] is its upper bound */
lk = u[k];
xassert(lk != +DBL_MAX);
}
else
{ /* actual lower bound of xB[i] is its original bound */
lk = l[k];
if (lk == -DBL_MAX)
continue;
}
/* determine teta on which xB[i] reaches its relaxed lower
* bound */
delta = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
if (beta[i] < lk)
teta = - delta / alfa;
else
teta = ((lk - delta) - beta[i]) / alfa;
}
else if (alfa >= +tol_piv)
{ /* xB[i] increases */
/* determine actual upper bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* actual upper bound of xB[i] is its lower bound */
uk = l[k];
xassert(uk != -DBL_MAX);
}
else if (phase == 1 && c[k] > 0.0)
{ /* xB[i] has no actual upper bound */
continue;
}
else
{ /* actual upper bound of xB[i] is its original bound */
uk = u[k];
if (uk == +DBL_MAX)
continue;
}
/* determine teta on which xB[i] reaches its relaxed upper
* bound */
delta = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
if (beta[i] > uk)
teta = + delta / alfa;
else
teta = ((uk + delta) - beta[i]) / alfa;
}
else
{ /* xB[i] does not depend on teta */
continue;
}
xassert(teta >= 0.0);
if (teta_min > teta)
teta_min = teta;
}
/*--------------------------------------------------------------*/
/* second pass: choose basic variable xB[p] */
/*--------------------------------------------------------------*/
k = head[m+q]; /* x[k] = xN[q] */
if (l[k] != -DBL_MAX && u[k] != +DBL_MAX)
{ /* xN[q] has both lower and upper bounds */
if (fabs(l[k] - u[k]) <= teta_min)
{ /* and reaches its opposite bound */
p = -1, *p_flag = 0;
goto done;
}
}
if (teta_min == DBL_MAX)
{ /* teta may increase unlimitedly */
p = 0, *p_flag = 0;
goto done;
}
/* nothing is chosen so far */
p = 0, *p_flag = 0, biga = 0.0;
/* walk thru the list of basic variables */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
/* determine alfa such that delta xB[i] = alfa * teta */
alfa = s * tcol[i];
if (alfa <= -tol_piv)
{ /* xB[i] decreases */
/* determine actual lower bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* xB[i] has no actual lower bound */
continue;
}
else if (phase == 1 && c[k] > 0.0)
{ /* actual lower bound of xB[i] is its upper bound */
lk = u[k];
xassert(lk != +DBL_MAX);
i_flag = 1;
}
else
{ /* actual lower bound of xB[i] is its original bound */
lk = l[k];
if (lk == -DBL_MAX)
continue;
i_flag = 0;
}
/* determine teta on which xB[i] reaches its lower bound */
teta = (lk - beta[i]) / alfa;
}
else if (alfa >= +tol_piv)
{ /* xB[i] increases */
/* determine actual upper bound of xB[i] */
if (phase == 1 && c[k] < 0.0)
{ /* actual upper bound of xB[i] is its lower bound */
uk = l[k];
xassert(uk != -DBL_MAX);
i_flag = 0;
}
else if (phase == 1 && c[k] > 0.0)
{ /* xB[i] has no actual upper bound */
continue;
}
else
{ /* actual upper bound of xB[i] is its original bound */
uk = u[k];
if (uk == +DBL_MAX)
continue;
i_flag = 1;
}
/* determine teta on which xB[i] reaches its upper bound */
teta = (uk - beta[i]) / alfa;
}
else
{ /* xB[i] does not depend on teta */
continue;
}
/* choose basic variable for which teta is not greater than
* teta_min determined for relaxed bounds and which has best
* (largest in magnitude) pivot */
alfa = (alfa >= 0.0 ? +alfa : -alfa);
if (teta <= teta_min && biga < alfa)
p = i, *p_flag = i_flag, biga = alfa;
}
/* something must be chosen */
xassert(1 <= p && p <= m);
/* if xB[p] is fixed variable, adjust its bound flag */
k = head[p];
if (l[k] == u[k])
*p_flag = 0;
done: return p;
}
#if 1 /* 22/VI-2017 */
/***********************************************************************
* spx_ls_eval_bp - determine penalty function break points
*
* This routine determines break points of the penalty function (which
* is the sum of primal infeasibilities).
*
* The parameters lp, beta, q, dq, tcol, and tol_piv have the same
* meaning as for the routine spx_chuzr_std (see above).
*
* The routine stores the break-points determined to the array elements
* bp[1], ..., bp[nbp] in *arbitrary* order, where 0 <= nbp <= 2*m+1 is
* the number of break-points returned by the routine on exit. */
int spx_ls_eval_bp(SPXLP *lp, const double beta[/*1+m*/],
int q, double dq, const double tcol[/*1+m*/], double tol_piv,
SPXBP bp[/*1+2*m+1*/])
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int i, k, nbp;
double s, alfa;
xassert(1 <= q && q <= n-m);
xassert(dq != 0.0);
s = (dq < 0.0 ? +1.0 : -1.0);
nbp = 0;
/* if chosen non-basic variable xN[q] is double-bounded, include
* it in the list, because it can cross its opposite bound */
k = head[m+q]; /* x[k] = xN[q] */
if (l[k] != -DBL_MAX && u[k] != +DBL_MAX)
{ nbp++;
bp[nbp].i = 0;
xassert(l[k] < u[k]); /* xN[q] cannot be fixed */
bp[nbp].teta = u[k] - l[k];
bp[nbp].dc = s;
}
/* build the list of all basic variables xB[i] that can cross
* their bound(s) for the ray parameter 0 <= teta < teta_max */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
xassert(l[k] <= u[k]);
/* determine alfa such that (delta xB[i]) = alfa * teta */
alfa = s * tcol[i];
if (alfa >= +tol_piv)
{ /* xB[i] increases on increasing teta */
if (l[k] == u[k])
{ /* xB[i] is fixed at lB[i] = uB[i] */
if (c[k] <= 0.0)
{ /* increasing xB[i] can cross its fixed value lB[i],
* because currently xB[i] <= lB[i] */
nbp++;
bp[nbp].i = +i;
bp[nbp].teta = (l[k] - beta[i]) / alfa;
/* if xB[i] > lB[i] then cB[i] = +1 */
bp[nbp].dc = +1.0 - c[k];
}
}
else
{ if (l[k] != -DBL_MAX && c[k] < 0.0)
{ /* increasing xB[i] can cross its lower bound lB[i],
* because currently xB[i] < lB[i] */
nbp++;
bp[nbp].i = +i;
bp[nbp].teta = (l[k] - beta[i]) / alfa;
bp[nbp].dc = +1.0;
}
if (u[k] != +DBL_MAX && c[k] <= 0.0)
{ /* increasing xB[i] can cross its upper bound uB[i],
* because currently xB[i] does not violate it */
nbp++;
bp[nbp].i = -i;
bp[nbp].teta = (u[k] - beta[i]) / alfa;
bp[nbp].dc = +1.0;
}
}
}
else if (alfa <= -tol_piv)
{ /* xB[i] decreases on increasing teta */
if (l[k] == u[k])
{ /* xB[i] is fixed at lB[i] = uB[i] */
if (c[k] >= 0.0)
{ /* decreasing xB[i] can cross its fixed value lB[i],
* because currently xB[i] >= lB[i] */
nbp++;
bp[nbp].i = +i;
bp[nbp].teta = (l[k] - beta[i]) / alfa;
/* if xB[i] < lB[i] then cB[i] = -1 */
bp[nbp].dc = -1.0 - c[k];
}
}
else
{ if (l[k] != -DBL_MAX && c[k] >= 0.0)
{ /* decreasing xB[i] can cross its lower bound lB[i],
* because currently xB[i] does not violate it */
nbp++;
bp[nbp].i = +i;
bp[nbp].teta = (l[k] - beta[i]) / alfa;
bp[nbp].dc = -1.0;
}
if (u[k] != +DBL_MAX && c[k] > 0.0)
{ /* decreasing xB[i] can cross its upper bound uB[i],
* because currently xB[i] > uB[i] */
nbp++;
bp[nbp].i = -i;
bp[nbp].teta = (u[k] - beta[i]) / alfa;
bp[nbp].dc = -1.0;
}
}
}
else
{ /* xB[i] does not depend on teta within a tolerance */
continue;
}
/* teta < 0 may happen only due to round-off errors when the
* current value of xB[i] is *close* to its (lower or upper)
* bound; in this case we replace teta by exact zero */
if (bp[nbp].teta < 0.0)
bp[nbp].teta = 0.0;
}
xassert(nbp <= 2*m+1);
return nbp;
}
#endif
#if 1 /* 22/VI-2017 */
/***********************************************************************
* spx_ls_select_bp - select and process penalty function break points
*
* This routine selects a next portion of the penalty function break
* points and processes them.
*
* On entry to the routine it is assumed that break points bp[1], ...,
* bp[num] are already processed, and slope is the penalty function
* slope to the right of the last processed break point bp[num].
* (Initially, when num = 0, slope should be specified as -fabs(d[q]),
* where d[q] is the reduced cost of chosen non-basic variable xN[q].)
*
* The routine selects break points among bp[num+1], ..., bp[nbp], for
* which teta <= teta_lim, and moves these break points to the array
* elements bp[num+1], ..., bp[num1], where num <= num1 <= 2*m+1 is the
* new number of processed break points returned by the routine on
* exit. Then the routine sorts the break points by ascending teta and
* computes the change of the penalty function relative to its value at
* teta = 0.
*
* On exit the routine also replaces the parameter slope with a new
* value that corresponds to the new last break-point bp[num1]. */
static int CDECL fcmp(const void *v1, const void *v2)
{ const SPXBP *p1 = v1, *p2 = v2;
if (p1->teta < p2->teta)
return -1;
else if (p1->teta > p2->teta)
return +1;
else
return 0;
}
int spx_ls_select_bp(SPXLP *lp, const double tcol[/*1+m*/],
int nbp, SPXBP bp[/*1+m+m+1*/], int num, double *slope, double
teta_lim)
{ int m = lp->m;
int i, t, num1;
double teta, dz;
xassert(0 <= num && num <= nbp && nbp <= m+m+1);
/* select a new portion of break points */
num1 = num;
for (t = num+1; t <= nbp; t++)
{ if (bp[t].teta <= teta_lim)
{ /* move break point to the beginning of the new portion */
num1++;
i = bp[num1].i, teta = bp[num1].teta, dz = bp[num1].dc;
bp[num1].i = bp[t].i, bp[num1].teta = bp[t].teta,
bp[num1].dc = bp[t].dc;
bp[t].i = i, bp[t].teta = teta, bp[t].dc = dz;
}
}
/* sort new break points bp[num+1], ..., bp[num1] by ascending
* the ray parameter teta */
if (num1 - num > 1)
qsort(&bp[num+1], num1 - num, sizeof(SPXBP), fcmp);
/* calculate the penalty function change at the new break points
* selected */
for (t = num+1; t <= num1; t++)
{ /* calculate the penalty function change relative to its value
* at break point bp[t-1] */
dz = (*slope) * (bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
/* calculate the penalty function change relative to its value
* at teta = 0 */
bp[t].dz = (t == 1 ? 0.0 : bp[t-1].dz) + dz;
/* calculate a new slope of the penalty function to the right
* of the current break point bp[t] */
i = (bp[t].i >= 0 ? bp[t].i : -bp[t].i);
xassert(0 <= i && i <= m);
if (i == 0)
*slope += fabs(1.0 * bp[t].dc);
else
*slope += fabs(tcol[i] * bp[t].dc);
}
return num1;
}
#endif
/* eof */
+75
View File
@@ -0,0 +1,75 @@
/* spxchuzr.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015-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/>.
***********************************************************************/
#ifndef SPXCHUZR_H
#define SPXCHUZR_H
#include "spxlp.h"
#define spx_chuzr_std _glp_spx_chuzr_std
int spx_chuzr_std(SPXLP *lp, int phase, const double beta[/*1+m*/],
int q, double s, const double tcol[/*1+m*/], int *p_flag,
double tol_piv, double tol, double tol1);
/* choose basic variable (textbook ratio test) */
#define spx_chuzr_harris _glp_spx_chuzr_harris
int spx_chuzr_harris(SPXLP *lp, int phase, const double beta[/*1+m*/],
int q, double s, const double tcol[/*1+m*/], int *p_flag,
double tol_piv, double tol, double tol1);
/* choose basic variable (Harris' ratio test) */
#if 1 /* 22/VI-2017 */
typedef struct SPXBP SPXBP;
struct SPXBP
{ /* penalty function (sum of infeasibilities) break point */
int i;
/* basic variable xB[i], 1 <= i <= m, that intersects its bound
* at this break point
* i > 0 if xB[i] intersects its lower bound (or fixed value)
* i < 0 if xB[i] intersects its upper bound
* i = 0 if xN[q] intersects its opposite bound */
double teta;
/* ray parameter value, teta >= 0, at this break point */
double dc;
/* increment of the penalty function coefficient cB[i] at this
* break point */
double dz;
/* increment, z[t] - z[0], of the penalty function at this break
* point */
};
#define spx_ls_eval_bp _glp_spx_ls_eval_bp
int spx_ls_eval_bp(SPXLP *lp, const double beta[/*1+m*/],
int q, double dq, const double tcol[/*1+m*/], double tol_piv,
SPXBP bp[/*1+2*m+1*/]);
/* determine penalty function break points */
#define spx_ls_select_bp _glp_spx_ls_select_bp
int spx_ls_select_bp(SPXLP *lp, const double tcol[/*1+m*/],
int nbp, SPXBP bp[/*1+m+m+1*/], int num, double *slope, double
teta_lim);
/* select and process penalty function break points */
#endif
#endif
/* eof */
+817
View File
@@ -0,0 +1,817 @@
/* spxlp.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spxlp.h"
/***********************************************************************
* spx_factorize - compute factorization of current basis matrix
*
* This routine computes factorization of the current basis matrix B.
*
* If the factorization has been successfully computed, the routine
* validates it and returns zero. Otherwise, the routine invalidates
* the factorization and returns the code provided by the factorization
* driver (bfd_factorize). */
static int jth_col(void *info, int j, int ind[], double val[])
{ /* provide column B[j] */
SPXLP *lp = info;
int m = lp->m;
int *A_ptr = lp->A_ptr;
int *head = lp->head;
int k, ptr, len;
xassert(1 <= j && j <= m);
k = head[j]; /* x[k] = xB[j] */
ptr = A_ptr[k];
len = A_ptr[k+1] - ptr;
memcpy(&ind[1], &lp->A_ind[ptr], len * sizeof(int));
memcpy(&val[1], &lp->A_val[ptr], len * sizeof(double));
return len;
}
int spx_factorize(SPXLP *lp)
{ int ret;
ret = bfd_factorize(lp->bfd, lp->m, jth_col, lp);
lp->valid = (ret == 0);
return ret;
}
/***********************************************************************
* spx_eval_beta - compute current values of basic variables
*
* This routine computes vector beta = (beta[i]) of current values of
* basic variables xB = (xB[i]). (Factorization of the current basis
* matrix should be valid.)
*
* First the routine computes a modified vector of right-hand sides:
*
* n-m
* y = b - N * f = b - sum N[j] * f[j],
* j=1
*
* where b = (b[i]) is the original vector of right-hand sides, N is
* a matrix composed from columns of the original constraint matrix A,
* which (columns) correspond to non-basic variables, f = (f[j]) is the
* vector of active bounds of non-basic variables xN = (xN[j]),
* N[j] = A[k] is a column of matrix A corresponding to non-basic
* variable xN[j] = x[k], f[j] is current active bound lN[j] = l[k] or
* uN[j] = u[k] of non-basic variable xN[j] = x[k]. The matrix-vector
* product N * f is computed as a linear combination of columns of N,
* so if f[j] = 0, column N[j] can be skipped.
*
* Then the routine performs FTRAN to compute the vector beta:
*
* beta = inv(B) * y.
*
* On exit the routine stores components of the vector beta to array
* locations beta[1], ..., beta[m]. */
void spx_eval_beta(SPXLP *lp, double beta[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
double *b = lp->b;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, k, ptr, end;
double fj, *y;
/* compute y = b - N * xN */
/* y := b */
y = beta;
memcpy(&y[1], &b[1], m * sizeof(double));
/* y := y - N * f */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* f[j] := active bound of xN[j] */
fj = flag[j] ? u[k] : l[k];
if (fj == 0.0 || fj == -DBL_MAX)
{ /* either xN[j] has zero active bound or it is unbounded;
* in the latter case its value is assumed to be zero */
continue;
}
/* y := y - N[j] * f[j] */
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
y[A_ind[ptr]] -= A_val[ptr] * fj;
}
/* compute beta = inv(B) * y */
xassert(lp->valid);
bfd_ftran(lp->bfd, beta);
return;
}
/***********************************************************************
* spx_eval_obj - compute current value of objective function
*
* This routine computes the value of the objective function in the
* current basic solution:
*
* z = cB'* beta + cN'* f + c[0] =
*
* m n-m
* = sum cB[i] * beta[i] + sum cN[j] * f[j] + c[0],
* i=1 j=1
*
* where cB = (cB[i]) is the vector of objective coefficients at basic
* variables, beta = (beta[i]) is the vector of current values of basic
* variables, cN = (cN[j]) is the vector of objective coefficients at
* non-basic variables, f = (f[j]) is the vector of current active
* bounds of non-basic variables, c[0] is the constant term of the
* objective function.
*
* It as assumed that components of the vector beta are stored in the
* array locations beta[1], ..., beta[m]. */
double spx_eval_obj(SPXLP *lp, const double beta[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int i, j, k;
double fj, z;
/* compute z = cB'* beta + cN'* f + c0 */
/* z := c0 */
z = c[0];
/* z := z + cB'* beta */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
z += c[k] * beta[i];
}
/* z := z + cN'* f */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* f[j] := active bound of xN[j] */
fj = flag[j] ? u[k] : l[k];
if (fj == 0.0 || fj == -DBL_MAX)
{ /* either xN[j] has zero active bound or it is unbounded;
* in the latter case its value is assumed to be zero */
continue;
}
z += c[k] * fj;
}
return z;
}
/***********************************************************************
* spx_eval_pi - compute simplex multipliers in current basis
*
* This routine computes vector pi = (pi[i]) of simplex multipliers in
* the current basis. (Factorization of the current basis matrix should
* be valid.)
*
* The vector pi is computed by performing BTRAN:
*
* pi = inv(B') * cB,
*
* where cB = (cB[i]) is the vector of objective coefficients at basic
* variables xB = (xB[i]).
*
* On exit components of vector pi are stored in the array locations
* pi[1], ..., pi[m]. */
void spx_eval_pi(SPXLP *lp, double pi[/*1+m*/])
{ int m = lp->m;
double *c = lp->c;
int *head = lp->head;
int i;
double *cB;
/* construct cB */
cB = pi;
for (i = 1; i <= m; i++)
cB[i] = c[head[i]];
/* compute pi = inv(B) * cB */
bfd_btran(lp->bfd, pi);
return;
}
/***********************************************************************
* spx_eval_dj - compute reduced cost of j-th non-basic variable
*
* This routine computes reduced cost d[j] of non-basic variable
* xN[j] = x[k], 1 <= j <= n-m, in the current basic solution:
*
* d[j] = c[k] - A'[k] * pi,
*
* where c[k] is the objective coefficient at x[k], A[k] is k-th column
* of the constraint matrix, pi is the vector of simplex multipliers in
* the current basis.
*
* It as assumed that components of the vector pi are stored in the
* array locations pi[1], ..., pi[m]. */
double spx_eval_dj(SPXLP *lp, const double pi[/*1+m*/], int j)
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int k, ptr, end;
double dj;
xassert(1 <= j && j <= n-m);
k = lp->head[m+j]; /* x[k] = xN[j] */
/* dj := c[k] */
dj = lp->c[k];
/* dj := dj - A'[k] * pi */
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
dj -= A_val[ptr] * pi[A_ind[ptr]];
return dj;
}
/***********************************************************************
* spx_eval_tcol - compute j-th column of simplex table
*
* This routine computes j-th column of the current simplex table
* T = (T[i,j]) = - inv(B) * N, 1 <= j <= n-m. (Factorization of the
* current basis matrix should be valid.)
*
* The simplex table column is computed by performing FTRAN:
*
* tcol = - inv(B) * N[j],
*
* where B is the current basis matrix, N[j] = A[k] is a column of the
* constraint matrix corresponding to non-basic variable xN[j] = x[k].
*
* On exit components of the simplex table column are stored in the
* array locations tcol[1], ... tcol[m]. */
void spx_eval_tcol(SPXLP *lp, int j, double tcol[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int *head = lp->head;
int i, k, ptr, end;
xassert(1 <= j && j <= n-m);
k = head[m+j]; /* x[k] = xN[j] */
/* compute tcol = - inv(B) * N[j] */
for (i = 1; i <= m; i++)
tcol[i] = 0.0;
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
tcol[A_ind[ptr]] = -A_val[ptr];
bfd_ftran(lp->bfd, tcol);
return;
}
/***********************************************************************
* spx_eval_rho - compute i-th row of basis matrix inverse
*
* This routine computes i-th row of the matrix inv(B), where B is
* the current basis matrix, 1 <= i <= m. (Factorization of the current
* basis matrix should be valid.)
*
* The inverse row is computed by performing BTRAN:
*
* rho = inv(B') * e[i],
*
* where e[i] is i-th column of unity matrix.
*
* On exit components of the row are stored in the array locations
* row[1], ..., row[m]. */
void spx_eval_rho(SPXLP *lp, int i, double rho[/*1+m*/])
{ int m = lp->m;
int j;
xassert(1 <= i && i <= m);
/* compute rho = inv(B') * e[i] */
for (j = 1; j <= m; j++)
rho[j] = 0.0;
rho[i] = 1.0;
bfd_btran(lp->bfd, rho);
return;
}
#if 1 /* 31/III-2016 */
void spx_eval_rho_s(SPXLP *lp, int i, FVS *rho)
{ /* sparse version of spx_eval_rho */
int m = lp->m;
xassert(1 <= i && i <= m);
/* compute rho = inv(B') * e[i] */
xassert(rho->n == m);
fvs_clear_vec(rho);
rho->nnz = 1;
rho->ind[1] = i;
rho->vec[i] = 1.0;
bfd_btran_s(lp->bfd, rho);
return;
}
#endif
/***********************************************************************
* spx_eval_tij - compute element T[i,j] of simplex table
*
* This routine computes element T[i,j] of the current simplex table
* T = - inv(B) * N, 1 <= i <= m, 1 <= j <= n-m, with the following
* formula:
*
* T[i,j] = - N'[j] * rho, (1)
*
* where N[j] = A[k] is a column of the constraint matrix corresponding
* to non-basic variable xN[j] = x[k], rho is i-th row of the inverse
* matrix inv(B).
*
* It as assumed that components of the inverse row rho = (rho[j]) are
* stored in the array locations rho[1], ..., rho[m]. */
double spx_eval_tij(SPXLP *lp, const double rho[/*1+m*/], int j)
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int k, ptr, end;
double tij;
xassert(1 <= j && j <= n-m);
k = lp->head[m+j]; /* x[k] = xN[j] */
/* compute t[i,j] = - N'[j] * pi */
tij = 0.0;
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
tij -= A_val[ptr] * rho[A_ind[ptr]];
return tij;
}
/***********************************************************************
* spx_eval_trow - compute i-th row of simplex table
*
* This routine computes i-th row of the current simplex table
* T = (T[i,j]) = - inv(B) * N, 1 <= i <= m.
*
* Elements of the row T[i] = (T[i,j]), j = 1, ..., n-m, are computed
* directly with the routine spx_eval_tij.
*
* The vector rho = (rho[j]), which is i-th row of the basis inverse
* inv(B), should be previously computed with the routine spx_eval_rho.
* It is assumed that elements of this vector are stored in the array
* locations rho[1], ..., rho[m].
*
* On exit components of the simplex table row are stored in the array
* locations trow[1], ... trow[n-m].
*
* NOTE: For testing/debugging only. */
void spx_eval_trow(SPXLP *lp, const double rho[/*1+m*/], double
trow[/*1+n-m*/])
{ int m = lp->m;
int n = lp->n;
int j;
for (j = 1; j <= n-m; j++)
trow[j] = spx_eval_tij(lp, rho, j);
return;
}
/***********************************************************************
* spx_update_beta - update values of basic variables
*
* This routine updates the vector beta = (beta[i]) of values of basic
* variables xB = (xB[i]) for the adjacent basis.
*
* On entry to the routine components of the vector beta in the current
* basis should be placed in array locations beta[1], ..., beta[m].
*
* The parameter 1 <= p <= m specifies basic variable xB[p] which
* becomes non-basic variable xN[q] in the adjacent basis. The special
* case p < 0 means that non-basic variable xN[q] goes from its current
* active bound to opposite one in the adjacent basis.
*
* If the flag p_flag is set, the active bound of xB[p] in the adjacent
* basis is set to its upper bound. (In this case xB[p] should have its
* upper bound and should not be fixed.)
*
* The parameter 1 <= q <= n-m specifies non-basic variable xN[q] which
* becomes basic variable xB[p] in the adjacent basis (if 1 <= p <= m),
* or goes to its opposite bound (if p < 0). (In the latter case xN[q]
* should have both lower and upper bounds and should not be fixed.)
*
* It is assumed that the array tcol contains elements of q-th (pivot)
* column T[q] of the simple table in locations tcol[1], ..., tcol[m].
* (This column should be computed for the current basis.)
*
* First, the routine determines the increment of basic variable xB[p]
* in the adjacent basis (but only if 1 <= p <= m):
*
* ( - beta[p], if -inf < xB[p] < +inf
* (
* delta xB[p] = { lB[p] - beta[p], if p_flag = 0
* (
* ( uB[p] - beta[p], if p_flag = 1
*
* where beta[p] is the value of xB[p] in the current basis, lB[p] and
* uB[p] are its lower and upper bounds. Then, the routine determines
* the increment of non-basic variable xN[q] in the adjacent basis:
*
* ( delta xB[p] / T[p,q], if 1 <= p <= m
* (
* delta xN[q] = { uN[q] - lN[q], if p < 0 and f[q] = lN[q]
* (
* ( lN[q] - uN[q], if p < 0 and f[q] = uN[q]
*
* where T[p,q] is the pivot element of the simplex table, f[q] is the
* active bound of xN[q] in the current basis.
*
* If 1 <= p <= m, in the adjacent basis xN[q] becomes xB[p], so:
*
* new beta[p] = f[q] + delta xN[q].
*
* Values of other basic variables xB[i] for 1 <= i <= m, i != p, are
* updated as follows:
*
* new beta[i] = beta[i] + T[i,q] * delta xN[q].
*
* On exit the routine stores updated components of the vector beta to
* the same locations, where the input vector beta was stored. */
void spx_update_beta(SPXLP *lp, double beta[/*1+m*/], int p,
int p_flag, int q, const double tcol[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int i, k;
double delta_p, delta_q;
if (p < 0)
{ /* special case: xN[q] goes to its opposite bound */
xassert(1 <= q && q <= n-m);
/* xN[q] should be double-bounded variable */
k = head[m+q]; /* x[k] = xN[q] */
xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
/* determine delta xN[q] */
if (flag[q])
{ /* xN[q] goes from its upper bound to its lower bound */
delta_q = l[k] - u[k];
}
else
{ /* xN[q] goes from its lower bound to its upper bound */
delta_q = u[k] - l[k];
}
}
else
{ /* xB[p] leaves the basis, xN[q] enters the basis */
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* determine delta xB[p] */
k = head[p]; /* x[k] = xB[p] */
if (p_flag)
{ /* xB[p] goes to its upper bound */
xassert(l[k] != u[k] && u[k] != +DBL_MAX);
delta_p = u[k] - beta[p];
}
else if (l[k] == -DBL_MAX)
{ /* unbounded xB[p] becomes non-basic (unusual case) */
xassert(u[k] == +DBL_MAX);
delta_p = 0.0 - beta[p];
}
else
{ /* xB[p] goes to its lower bound or becomes fixed */
delta_p = l[k] - beta[p];
}
/* determine delta xN[q] */
delta_q = delta_p / tcol[p];
/* compute new beta[p], which is the value of xN[q] in the
* adjacent basis */
k = head[m+q]; /* x[k] = xN[q] */
if (flag[q])
{ /* xN[q] has its upper bound active */
xassert(l[k] != u[k] && u[k] != +DBL_MAX);
beta[p] = u[k] + delta_q;
}
else if (l[k] == -DBL_MAX)
{ /* xN[q] is non-basic unbounded variable */
xassert(u[k] == +DBL_MAX);
beta[p] = 0.0 + delta_q;
}
else
{ /* xN[q] has its lower bound active or is fixed (latter
* case is unusual) */
beta[p] = l[k] + delta_q;
}
}
/* compute new beta[i] for all i != p */
for (i = 1; i <= m; i++)
{ if (i != p)
beta[i] += tcol[i] * delta_q;
}
return;
}
#if 1 /* 30/III-2016 */
void spx_update_beta_s(SPXLP *lp, double beta[/*1+m*/], int p,
int p_flag, int q, const FVS *tcol)
{ /* sparse version of spx_update_beta */
int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int nnz = tcol->nnz;
int *ind = tcol->ind;
double *vec = tcol->vec;
int i, k;
double delta_p, delta_q;
xassert(tcol->n == m);
if (p < 0)
{ /* special case: xN[q] goes to its opposite bound */
#if 0 /* 11/VI-2017 */
/* FIXME: not tested yet */
xassert(0);
#endif
xassert(1 <= q && q <= n-m);
/* xN[q] should be double-bounded variable */
k = head[m+q]; /* x[k] = xN[q] */
xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
/* determine delta xN[q] */
if (flag[q])
{ /* xN[q] goes from its upper bound to its lower bound */
delta_q = l[k] - u[k];
}
else
{ /* xN[q] goes from its lower bound to its upper bound */
delta_q = u[k] - l[k];
}
}
else
{ /* xB[p] leaves the basis, xN[q] enters the basis */
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* determine delta xB[p] */
k = head[p]; /* x[k] = xB[p] */
if (p_flag)
{ /* xB[p] goes to its upper bound */
xassert(l[k] != u[k] && u[k] != +DBL_MAX);
delta_p = u[k] - beta[p];
}
else if (l[k] == -DBL_MAX)
{ /* unbounded xB[p] becomes non-basic (unusual case) */
xassert(u[k] == +DBL_MAX);
delta_p = 0.0 - beta[p];
}
else
{ /* xB[p] goes to its lower bound or becomes fixed */
delta_p = l[k] - beta[p];
}
/* determine delta xN[q] */
delta_q = delta_p / vec[p];
/* compute new beta[p], which is the value of xN[q] in the
* adjacent basis */
k = head[m+q]; /* x[k] = xN[q] */
if (flag[q])
{ /* xN[q] has its upper bound active */
xassert(l[k] != u[k] && u[k] != +DBL_MAX);
beta[p] = u[k] + delta_q;
}
else if (l[k] == -DBL_MAX)
{ /* xN[q] is non-basic unbounded variable */
xassert(u[k] == +DBL_MAX);
beta[p] = 0.0 + delta_q;
}
else
{ /* xN[q] has its lower bound active or is fixed (latter
* case is unusual) */
beta[p] = l[k] + delta_q;
}
}
/* compute new beta[i] for all i != p */
for (k = 1; k <= nnz; k++)
{ i = ind[k];
if (i != p)
beta[i] += vec[i] * delta_q;
}
return;
}
#endif
/***********************************************************************
* spx_update_d - update reduced costs of non-basic variables
*
* This routine updates the vector d = (d[j]) of reduced costs of
* non-basic variables xN = (xN[j]) for the adjacent basis.
*
* On entry to the routine components of the vector d in the current
* basis should be placed in locations d[1], ..., d[n-m].
*
* The parameter 1 <= p <= m specifies basic variable xB[p] which
* becomes non-basic variable xN[q] in the adjacent basis.
*
* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
* becomes basic variable xB[p] in the adjacent basis.
*
* It is assumed that the array trow contains elements of p-th (pivot)
* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
* It is also assumed that the array tcol contains elements of q-th
* (pivot) column T[q] of the simple table in locations tcol[1], ...,
* tcol[m]. (These row and column should be computed for the current
* basis.)
*
* First, the routine computes more accurate reduced cost d[q] in the
* current basis using q-th column of the simplex table:
*
* n-m
* d[q] = cN[q] + sum t[i,q] * cB[i],
* i=1
*
* where cN[q] and cB[i] are objective coefficients at variables xN[q]
* and xB[i], resp. The routine also computes the relative error:
*
* e = |d[q] - d'[q]| / (1 + |d[q]|),
*
* where d'[q] is the reduced cost of xN[q] on entry to the routine,
* and returns e on exit. (If e happens to be large enough, the calling
* program may compute the reduced costs directly, since other reduced
* costs also may be inaccurate.)
*
* In the adjacent basis xB[p] becomes xN[q], so:
*
* new d[q] = d[q] / T[p,q],
*
* where T[p,q] is the pivot element of the simplex table (it is taken
* from column T[q] as more accurate). Reduced costs of other non-basic
* variables xN[j] for 1 <= j <= n-m, j != q, are updated as follows:
*
* new d[j] = d[j] + T[p,j] * new d[q].
*
* On exit the routine stores updated components of the vector d to the
* same locations, where the input vector d was stored. */
double spx_update_d(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
int *head = lp->head;
int i, j, k;
double dq, e;
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n);
/* compute d[q] in current basis more accurately */
k = head[m+q]; /* x[k] = xN[q] */
dq = c[k];
for (i = 1; i <= m; i++)
dq += tcol[i] * c[head[i]];
/* compute relative error in d[q] */
e = fabs(dq - d[q]) / (1.0 + fabs(dq));
/* compute new d[q], which is the reduced cost of xB[p] in the
* adjacent basis */
d[q] = (dq /= tcol[p]);
/* compute new d[j] for all j != q */
for (j = 1; j <= n-m; j++)
{ if (j != q)
d[j] -= trow[j] * dq;
}
return e;
}
#if 1 /* 30/III-2016 */
double spx_update_d_s(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
const FVS *trow, const FVS *tcol)
{ /* sparse version of spx_update_d */
int m = lp->m;
int n = lp->n;
double *c = lp->c;
int *head = lp->head;
int trow_nnz = trow->nnz;
int *trow_ind = trow->ind;
double *trow_vec = trow->vec;
int tcol_nnz = tcol->nnz;
int *tcol_ind = tcol->ind;
double *tcol_vec = tcol->vec;
int i, j, k;
double dq, e;
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n);
xassert(trow->n == n-m);
xassert(tcol->n == m);
/* compute d[q] in current basis more accurately */
k = head[m+q]; /* x[k] = xN[q] */
dq = c[k];
for (k = 1; k <= tcol_nnz; k++)
{ i = tcol_ind[k];
dq += tcol_vec[i] * c[head[i]];
}
/* compute relative error in d[q] */
e = fabs(dq - d[q]) / (1.0 + fabs(dq));
/* compute new d[q], which is the reduced cost of xB[p] in the
* adjacent basis */
d[q] = (dq /= tcol_vec[p]);
/* compute new d[j] for all j != q */
for (k = 1; k <= trow_nnz; k++)
{ j = trow_ind[k];
if (j != q)
d[j] -= trow_vec[j] * dq;
}
return e;
}
#endif
/***********************************************************************
* spx_change_basis - change current basis to adjacent one
*
* This routine changes the current basis to the adjacent one making
* necessary changes in lp->head and lp->flag members.
*
* The parameters p, p_flag, and q have the same meaning as for the
* routine spx_update_beta. */
void spx_change_basis(SPXLP *lp, int p, int p_flag, int q)
{ int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int k;
if (p < 0)
{ /* special case: xN[q] goes to its opposite bound */
xassert(1 <= q && q <= n-m);
/* xN[q] should be double-bounded variable */
k = head[m+q]; /* x[k] = xN[q] */
xassert(l[k] != -DBL_MAX && u[k] != +DBL_MAX && l[k] != u[k]);
/* change active bound flag */
flag[q] = 1 - flag[q];
}
else
{ /* xB[p] leaves the basis, xN[q] enters the basis */
xassert(1 <= p && p <= m);
xassert(p_flag == 0 || p_flag == 1);
xassert(1 <= q && q <= n-m);
k = head[p]; /* xB[p] = x[k] */
if (p_flag)
{ /* xB[p] goes to its upper bound */
xassert(l[k] != u[k] && u[k] != +DBL_MAX);
}
/* swap xB[p] and xN[q] in the basis */
head[p] = head[m+q], head[m+q] = k;
/* and set active bound flag for new xN[q] */
lp->flag[q] = p_flag;
}
return;
}
/***********************************************************************
* spx_update_invb - update factorization of basis matrix
*
* This routine updates factorization of the basis matrix B when i-th
* column of B is replaced by k-th column of the constraint matrix A.
*
* The parameter 1 <= i <= m specifies the number of column of matrix B
* to be replaced by a new column.
*
* The parameter 1 <= k <= n specifies the number of column of matrix A
* to be used for replacement.
*
* If the factorization has been successfully updated, the routine
* validates it and returns zero. Otherwise, the routine invalidates
* the factorization and returns the code provided by the factorization
* driver (bfd_update). */
int spx_update_invb(SPXLP *lp, int i, int k)
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int ptr, len, ret;
xassert(1 <= i && i <= m);
xassert(1 <= k && k <= n);
ptr = A_ptr[k];
len = A_ptr[k+1] - ptr;
ret = bfd_update(lp->bfd, i, len, &A_ind[ptr-1], &A_val[ptr-1]);
lp->valid = (ret == 0);
return ret;
}
/* eof */
+232
View File
@@ -0,0 +1,232 @@
/* spxlp.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPXLP_H
#define SPXLP_H
#include "bfd.h"
/***********************************************************************
* The structure SPXLP describes LP problem and its current basis.
*
* It is assumed that LP problem has the following formulation (this is
* so called "working format"):
*
* z = c'* x + c0 -> min (1)
*
* A * x = b (2)
*
* l <= x <= u (3)
*
* where:
*
* x = (x[k]) is a n-vector of variables;
*
* z is an objective function;
*
* c = (c[k]) is a n-vector of objective coefficients;
*
* c0 is a constant term of the objective function;
*
* A = (a[i,k]) is a mxn-matrix of constraint coefficients;
*
* b = (b[i]) is a m-vector of right-hand sides;
*
* l = (l[k]) is a n-vector of lower bounds of variables;
*
* u = (u[k]) is a n-vector of upper bounds of variables.
*
* If variable x[k] has no lower (upper) bound, it is formally assumed
* that l[k] = -inf (u[k] = +inf). Variable having no bounds is called
* free (unbounded) variable. If l[k] = u[k], variable x[k] is assumed
* to be fixed.
*
* It is also assumed that matrix A has full row rank: rank(A) = m,
* i.e. all its rows are linearly independent, so m <= n.
*
* The (current) basis is defined by an appropriate permutation matrix
* P of order n such that:
*
* ( xB )
* P * x = ( ), (4)
* ( xN )
*
* where xB = (xB[i]) is a m-vector of basic variables, xN = (xN[j]) is
* a (n-m)-vector of non-basic variables. If a non-basic variable xN[j]
* has both lower and upper bounds, there is used an additional flag to
* indicate which bound is active.
*
* From (2) and (4) it follows that:
*
* A * P'* P * x = b <=> B * xB + N * xN = b, (5)
*
* where P' is a matrix transposed to P, and
*
* A * P' = (B | N). (6)
*
* Here B is the basis matrix, which is a square non-singular matrix
* of order m composed from columns of matrix A that correspond to
* basic variables xB, and N is a mx(n-m) matrix composed from columns
* of matrix A that correspond to non-basic variables xN. */
typedef struct SPXLP SPXLP;
struct SPXLP
{ /* LP problem data and its (current) basis */
int m;
/* number of equality constraints, m > 0 */
int n;
/* number of variables, n >= m */
int nnz;
/* number of non-zeros in constraint matrix A */
/*--------------------------------------------------------------*/
/* mxn-matrix A of constraint coefficients in sparse column-wise
* format */
int *A_ptr; /* int A_ptr[1+n+1]; */
/* A_ptr[0] is not used;
* A_ptr[k], 1 <= k <= n, is starting position of k-th column in
* arrays A_ind and A_val; note that A_ptr[1] is always 1;
* A_ptr[n+1] indicates the position after the last element in
* arrays A_ind and A_val, i.e. A_ptr[n+1] = nnz+1, where nnz is
* the number of non-zero elements in matrix A;
* the length of k-th column (the number of non-zero elements in
* that column) can be calculated as A_ptr[k+1] - A_ptr[k] */
int *A_ind; /* int A_ind[1+nnz]; */
/* row indices */
double *A_val; /* double A_val[1+nnz]; */
/* non-zero element values (constraint coefficients) */
/*--------------------------------------------------------------*/
/* principal vectors of LP formulation */
double *b; /* double b[1+m]; */
/* b[0] is not used;
* b[i], 1 <= i <= m, is the right-hand side of i-th equality
* constraint */
double *c; /* double c[1+n]; */
/* c[0] is the constant term of the objective function;
* c[k], 1 <= k <= n, is the objective function coefficient at
* variable x[k] */
double *l; /* double l[1+n]; */
/* l[0] is not used;
* l[k], 1 <= k <= n, is the lower bound of variable x[k];
* if x[k] has no lower bound, l[k] = -DBL_MAX */
double *u; /* double u[1+n]; */
/* u[0] is not used;
* u[k], 1 <= k <= n, is the upper bound of variable u[k];
* if x[k] has no upper bound, u[k] = +DBL_MAX;
* note that l[k] = u[k] means that x[k] is fixed variable */
/*--------------------------------------------------------------*/
/* LP basis */
int *head; /* int head[1+n]; */
/* basis header, which is permutation matrix P (4):
* head[0] is not used;
* head[i] = k means that xB[i] = x[k], 1 <= i <= m;
* head[m+j] = k, means that xN[j] = x[k], 1 <= j <= n-m */
char *flag; /* char flag[1+n-m]; */
/* flags of non-basic variables:
* flag[0] is not used;
* flag[j], 1 <= j <= n-m, indicates that non-basic variable
* xN[j] is non-fixed and has its upper bound active */
/*--------------------------------------------------------------*/
/* basis matrix B of order m stored in factorized form */
int valid;
/* factorization validity flag */
BFD *bfd;
/* driver to factorization of the basis matrix */
};
#define spx_factorize _glp_spx_factorize
int spx_factorize(SPXLP *lp);
/* compute factorization of current basis matrix */
#define spx_eval_beta _glp_spx_eval_beta
void spx_eval_beta(SPXLP *lp, double beta[/*1+m*/]);
/* compute values of basic variables */
#define spx_eval_obj _glp_spx_eval_obj
double spx_eval_obj(SPXLP *lp, const double beta[/*1+m*/]);
/* compute value of objective function */
#define spx_eval_pi _glp_spx_eval_pi
void spx_eval_pi(SPXLP *lp, double pi[/*1+m*/]);
/* compute simplex multipliers */
#define spx_eval_dj _glp_spx_eval_dj
double spx_eval_dj(SPXLP *lp, const double pi[/*1+m*/], int j);
/* compute reduced cost of j-th non-basic variable */
#define spx_eval_tcol _glp_spx_eval_tcol
void spx_eval_tcol(SPXLP *lp, int j, double tcol[/*1+m*/]);
/* compute j-th column of simplex table */
#define spx_eval_rho _glp_spx_eval_rho
void spx_eval_rho(SPXLP *lp, int i, double rho[/*1+m*/]);
/* compute i-th row of basis matrix inverse */
#if 1 /* 31/III-2016 */
#define spx_eval_rho_s _glp_spx_eval_rho_s
void spx_eval_rho_s(SPXLP *lp, int i, FVS *rho);
/* sparse version of spx_eval_rho */
#endif
#define spx_eval_tij _glp_spx_eval_tij
double spx_eval_tij(SPXLP *lp, const double rho[/*1+m*/], int j);
/* compute element T[i,j] of simplex table */
#define spx_eval_trow _glp_spx_eval_trow
void spx_eval_trow(SPXLP *lp, const double rho[/*1+m*/], double
trow[/*1+n-m*/]);
/* compute i-th row of simplex table */
#define spx_update_beta _glp_spx_update_beta
void spx_update_beta(SPXLP *lp, double beta[/*1+m*/], int p,
int p_flag, int q, const double tcol[/*1+m*/]);
/* update values of basic variables */
#if 1 /* 30/III-2016 */
#define spx_update_beta_s _glp_spx_update_beta_s
void spx_update_beta_s(SPXLP *lp, double beta[/*1+m*/], int p,
int p_flag, int q, const FVS *tcol);
/* sparse version of spx_update_beta */
#endif
#define spx_update_d _glp_spx_update_d
double spx_update_d(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
/* update reduced costs of non-basic variables */
#if 1 /* 30/III-2016 */
#define spx_update_d_s _glp_spx_update_d_s
double spx_update_d_s(SPXLP *lp, double d[/*1+n-m*/], int p, int q,
const FVS *trow, const FVS *tcol);
/* sparse version of spx_update_d */
#endif
#define spx_change_basis _glp_spx_change_basis
void spx_change_basis(SPXLP *lp, int p, int p_flag, int q);
/* change current basis to adjacent one */
#define spx_update_invb _glp_spx_update_invb
int spx_update_invb(SPXLP *lp, int i, int k);
/* update factorization of basis matrix */
#endif
/* eof */
+301
View File
@@ -0,0 +1,301 @@
/* spxnt.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spxnt.h"
/***********************************************************************
* spx_alloc_nt - allocate matrix N in sparse row-wise format
*
* This routine allocates the memory for arrays needed to represent the
* matrix N composed of non-basic columns of the constraint matrix A. */
void spx_alloc_nt(SPXLP *lp, SPXNT *nt)
{ int m = lp->m;
int nnz = lp->nnz;
nt->ptr = talloc(1+m, int);
nt->len = talloc(1+m, int);
nt->ind = talloc(1+nnz, int);
nt->val = talloc(1+nnz, double);
return;
}
/***********************************************************************
* spx_init_nt - initialize row pointers for matrix N
*
* This routine initializes (sets up) row pointers for the matrix N
* using column-wise representation of the constraint matrix A.
*
* This routine needs to be called only once. */
void spx_init_nt(SPXLP *lp, SPXNT *nt)
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
int *NT_ptr = nt->ptr;
int *NT_len = nt->len;
int i, k, ptr, end;
/* calculate NT_len[i] = maximal number of non-zeros in i-th row
* of N = number of non-zeros in i-th row of A */
memset(&NT_len[1], 0, m * sizeof(int));
for (k = 1; k <= n; k++)
{ ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
NT_len[A_ind[ptr]]++;
}
/* initialize row pointers NT_ptr[i], i = 1,...,n-m */
NT_ptr[1] = 1;
for (i = 2; i <= m; i++)
NT_ptr[i] = NT_ptr[i-1] + NT_len[i-1];
xassert(NT_ptr[m] + NT_len[m] == nnz+1);
return;
}
/***********************************************************************
* spx_nt_add_col - add column N[j] = A[k] to matrix N
*
* This routine adds elements of column N[j] = A[k], 1 <= j <= n-m,
* 1 <= k <= n, to the row-wise represntation of the matrix N. It is
* assumed (with no check) that elements of the specified column are
* missing in the row-wise represntation of N. */
void spx_nt_add_col(SPXLP *lp, SPXNT *nt, int j, int k)
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
int *NT_ptr = nt->ptr;
int *NT_len = nt->len;
int *NT_ind = nt->ind;
double *NT_val = nt->val;
int i, ptr, end, pos;
xassert(1 <= j && j <= n-m);
xassert(1 <= k && k <= n);
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
{ i = A_ind[ptr];
/* add element N[i,j] = A[i,k] to i-th row of matrix N */
pos = NT_ptr[i] + (NT_len[i]++);
if (i < m)
xassert(pos < NT_ptr[i+1]);
else
xassert(pos <= nnz);
NT_ind[pos] = j;
NT_val[pos] = A_val[ptr];
}
return;
}
/***********************************************************************
* spx_build_nt - build matrix N for current basis
*
* This routine builds the row-wise represntation of the matrix N
* for the current basis by adding columns of the constraint matrix A
* corresponding to non-basic variables. */
void spx_build_nt(SPXLP *lp, SPXNT *nt)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
int *NT_len = nt->len;
int j, k;
/* N := 0 */
memset(&NT_len[1], 0, m * sizeof(int));
/* add non-basic columns N[j] = A[k] */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
spx_nt_add_col(lp, nt, j, k);
}
return;
}
/***********************************************************************
* spx_nt_del_col - remove column N[j] = A[k] from matrix N
*
* This routine removes elements of column N[j] = A[k], 1 <= j <= n-m,
* 1 <= k <= n, from the row-wise representation of the matrix N. It is
* assumed (with no check) that elements of the specified column are
* present in the row-wise representation of N. */
void spx_nt_del_col(SPXLP *lp, SPXNT *nt, int j, int k)
{ int m = lp->m;
int n = lp->n;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
int *NT_ptr = nt->ptr;
int *NT_len = nt->len;
int *NT_ind = nt->ind;
double *NT_val = nt->val;
int i, ptr, end, ptr1, end1;
xassert(1 <= j && j <= n-m);
xassert(1 <= k && k <= n);
ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
{ i = A_ind[ptr];
/* find element N[i,j] = A[i,k] in i-th row of matrix N */
ptr1 = NT_ptr[i];
end1 = ptr1 + NT_len[i];
for (; NT_ind[ptr1] != j; ptr1++)
/* nop */;
xassert(ptr1 < end1);
/* and remove it from i-th row element list */
NT_len[i]--;
NT_ind[ptr1] = NT_ind[end1-1];
NT_val[ptr1] = NT_val[end1-1];
}
return;
}
/***********************************************************************
* spx_update_nt - update matrix N for adjacent basis
*
* This routine updates the row-wise represntation of matrix N for
* the adjacent basis, where column N[q], 1 <= q <= n-m, is replaced by
* column B[p], 1 <= p <= m, of the current basis matrix B. */
void spx_update_nt(SPXLP *lp, SPXNT *nt, int p, int q)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* remove old column N[q] corresponding to variable xN[q] */
spx_nt_del_col(lp, nt, q, head[m+q]);
/* add new column N[q] corresponding to variable xB[p] */
spx_nt_add_col(lp, nt, q, head[p]);
return;
}
/***********************************************************************
* spx_nt_prod - compute product y := y + s * N'* x
*
* This routine computes the product:
*
* y := y + s * N'* x,
*
* where N' is a matrix transposed to the mx(n-m)-matrix N composed
* from non-basic columns of the constraint matrix A, x is a m-vector,
* s is a scalar, y is (n-m)-vector.
*
* If the flag ign is non-zero, the routine ignores the input content
* of the array y assuming that y = 0.
*
* The routine uses the row-wise representation of the matrix N and
* computes the product as a linear combination:
*
* y := y + s * (N'[1] * x[1] + ... + N'[m] * x[m]),
*
* where N'[i] is i-th row of N, 1 <= i <= m. */
void spx_nt_prod(SPXLP *lp, SPXNT *nt, double y[/*1+n-m*/], int ign,
double s, const double x[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *NT_ptr = nt->ptr;
int *NT_len = nt->len;
int *NT_ind = nt->ind;
double *NT_val = nt->val;
int i, j, ptr, end;
double t;
if (ign)
{ /* y := 0 */
for (j = 1; j <= n-m; j++)
y[j] = 0.0;
}
for (i = 1; i <= m; i++)
{ if (x[i] != 0.0)
{ /* y := y + s * (i-th row of N) * x[i] */
t = s * x[i];
ptr = NT_ptr[i];
end = ptr + NT_len[i];
for (; ptr < end; ptr++)
y[NT_ind[ptr]] += NT_val[ptr] * t;
}
}
return;
}
#if 1 /* 31/III-2016 */
void spx_nt_prod_s(SPXLP *lp, SPXNT *nt, FVS *y, int ign, double s,
const FVS *x, double eps)
{ /* sparse version of spx_nt_prod */
int *NT_ptr = nt->ptr;
int *NT_len = nt->len;
int *NT_ind = nt->ind;
double *NT_val = nt->val;
int *x_ind = x->ind;
double *x_vec = x->vec;
int *y_ind = y->ind;
double *y_vec = y->vec;
int i, j, k, nnz, ptr, end;
double t;
xassert(x->n == lp->m);
xassert(y->n == lp->n-lp->m);
if (ign)
{ /* y := 0 */
fvs_clear_vec(y);
}
nnz = y->nnz;
for (k = x->nnz; k >= 1; k--)
{ i = x_ind[k];
/* y := y + s * (i-th row of N) * x[i] */
t = s * x_vec[i];
ptr = NT_ptr[i];
end = ptr + NT_len[i];
for (; ptr < end; ptr++)
{ j = NT_ind[ptr];
if (y_vec[j] == 0.0)
y_ind[++nnz] = j;
y_vec[j] += NT_val[ptr] * t;
/* don't forget about numeric cancellation */
if (y_vec[j] == 0.0)
y_vec[j] = DBL_MIN;
}
}
y->nnz = nnz;
fvs_adjust_vec(y, eps);
return;
}
#endif
/***********************************************************************
* spx_free_nt - deallocate matrix N in sparse row-wise format
*
* This routine deallocates the memory used for arrays of the program
* object nt. */
void spx_free_nt(SPXLP *lp, SPXNT *nt)
{ xassert(lp == lp);
tfree(nt->ptr);
tfree(nt->len);
tfree(nt->ind);
tfree(nt->val);
return;
}
/* eof */
+94
View File
@@ -0,0 +1,94 @@
/* spxnt.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPXNT_H
#define SPXNT_H
#include "spxlp.h"
typedef struct SPXNT SPXNT;
struct SPXNT
{ /* mx(n-m)-matrix N composed of non-basic columns of constraint
* matrix A, in sparse row-wise format */
int *ptr; /* int ptr[1+m]; */
/* ptr[0] is not used;
* ptr[i], 1 <= i <= m, is starting position of i-th row in
* arrays ind and val; note that ptr[1] is always 1;
* these starting positions are set up *once* as if they would
* correspond to rows of matrix A stored without gaps, i.e.
* ptr[i+1] - ptr[i] is the number of non-zeros in i-th (i < m)
* row of matrix A, and (nnz+1) - ptr[m] is the number of
* non-zero in m-th (last) row of matrix A, where nnz is the
* total number of non-zeros in matrix A */
int *len; /* int len[1+m]; */
/* len[0] is not used;
* len[i], 1 <= i <= m, is the number of non-zeros in i-th row
* of current matrix N */
int *ind; /* int ind[1+nnz]; */
/* column indices */
double *val; /* double val[1+nnz]; */
/* non-zero element values */
};
#define spx_alloc_nt _glp_spx_alloc_nt
void spx_alloc_nt(SPXLP *lp, SPXNT *nt);
/* allocate matrix N in sparse row-wise format */
#define spx_init_nt _glp_spx_init_nt
void spx_init_nt(SPXLP *lp, SPXNT *nt);
/* initialize row pointers for matrix N */
#define spx_nt_add_col _glp_spx_nt_add_col
void spx_nt_add_col(SPXLP *lp, SPXNT *nt, int j, int k);
/* add column N[j] = A[k] */
#define spx_build_nt _glp_spx_build_nt
void spx_build_nt(SPXLP *lp, SPXNT *nt);
/* build matrix N for current basis */
#define spx_nt_del_col _glp_spx_nt_del_col
void spx_nt_del_col(SPXLP *lp, SPXNT *nt, int j, int k);
/* remove column N[j] = A[k] from matrix N */
#define spx_update_nt _glp_spx_update_nt
void spx_update_nt(SPXLP *lp, SPXNT *nt, int p, int q);
/* update matrix N for adjacent basis */
#define spx_nt_prod _glp_spx_nt_prod
void spx_nt_prod(SPXLP *lp, SPXNT *nt, double y[/*1+n-m*/], int ign,
double s, const double x[/*1+m*/]);
/* compute product y := y + s * N'* x */
#if 1 /* 31/III-2016 */
#define spx_nt_prod_s _glp_spx_nt_prod_s
void spx_nt_prod_s(SPXLP *lp, SPXNT *nt, FVS *y, int ign, double s,
const FVS *x, double eps);
/* sparse version of spx_nt_prod */
#endif
#define spx_free_nt _glp_spx_free_nt
void spx_free_nt(SPXLP *lp, SPXNT *nt);
/* deallocate matrix N in sparse row-wise format */
#endif
/* eof */
File diff suppressed because it is too large Load Diff
+677
View File
@@ -0,0 +1,677 @@
/* spxprob.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spxprob.h"
/***********************************************************************
* spx_init_lp - initialize working LP object
*
* This routine determines the number of equality constraints m, the
* number of variables n, and the number of non-zero elements nnz in
* the constraint matrix for the working LP, which corresponds to the
* original LP, and stores these dimensions to the working LP object.
* (The working LP object should be allocated by the calling routine.)
*
* If the flag excl is set, the routine assumes that non-basic fixed
* variables will be excluded from the working LP. */
void spx_init_lp(SPXLP *lp, glp_prob *P, int excl)
{ int i, j, m, n, nnz;
m = P->m;
xassert(m > 0);
n = 0;
nnz = P->nnz;
xassert(P->valid);
/* scan rows of original LP */
for (i = 1; i <= m; i++)
{ GLPROW *row = P->row[i];
if (excl && row->stat == GLP_NS)
{ /* skip non-basic fixed auxiliary variable */
/* nop */
}
else
{ /* include auxiliary variable in working LP */
n++;
nnz++; /* unity column */
}
}
/* scan columns of original LP */
for (j = 1; j <= P->n; j++)
{ GLPCOL *col = P->col[j];
if (excl && col->stat == GLP_NS)
{ /* skip non-basic fixed structural variable */
GLPAIJ *aij;
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
nnz--;
}
else
{ /* include structural variable in working LP */
n++;
}
}
/* initialize working LP data block */
memset(lp, 0, sizeof(SPXLP));
lp->m = m;
xassert(n > 0);
lp->n = n;
lp->nnz = nnz;
return;
}
/***********************************************************************
* spx_alloc_lp - allocate working LP arrays
*
* This routine allocates the memory for all arrays in the working LP
* object. */
void spx_alloc_lp(SPXLP *lp)
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
lp->A_ptr = talloc(1+n+1, int);
lp->A_ind = talloc(1+nnz, int);
lp->A_val = talloc(1+nnz, double);
lp->b = talloc(1+m, double);
lp->c = talloc(1+n, double);
lp->l = talloc(1+n, double);
lp->u = talloc(1+n, double);
lp->head = talloc(1+n, int);
lp->flag = talloc(1+n-m, char);
return;
}
/***********************************************************************
* spx_build_lp - convert original LP to working LP
*
* This routine converts components (except the current basis) of the
* original LP to components of the working LP and perform scaling of
* these components. Also, if the original LP is maximization, the
* routine changes the signs of the objective coefficients and constant
* term to opposite ones.
*
* If the flag excl is set, original non-basic fixed variables are
* *not* included in the working LP. Otherwise, all (auxiliary and
* structural) original variables are included in the working LP. Note
* that this flag should have the same value as it has in a call to the
* routine spx_init_lp.
*
* If the flag shift is set, the routine shift bounds of variables
* included in the working LP to make at least one bound to be zero.
* If a variable has both lower and upper bounds, the bound having
* smaller magnitude is shifted to zero.
*
* On exit the routine stores information about correspondence between
* numbers of variables in the original and working LPs to the array
* map, which should have 1+P->m+P->n locations (location [0] is not
* used), where P->m is the numbers of rows and P->n is the number of
* columns in the original LP:
*
* map[i] = +k, 1 <= i <= P->m, means that i-th auxiliary variable of
* the original LP corresponds to variable x[k] of the working LP;
*
* map[i] = -k, 1 <= i <= P->m, means that i-th auxiliary variable of
* the original LP corresponds to variable x[k] of the working LP, and
* the upper bound of that variable was shifted to zero;
*
* map[i] = 0, 1 <= i <= P->m, means that i-th auxiliary variable of
* the original LP was excluded from the working LP;
*
* map[P->m+j], 1 <= j <= P->n, has the same sense as above, however,
* for j-th structural variable of the original LP. */
void spx_build_lp(SPXLP *lp, glp_prob *P, int excl, int shift,
int map[/*1+P->m+P->n*/])
{ int m = lp->m;
int n = lp->n;
int nnz = lp->nnz;
int *A_ptr = lp->A_ptr;
int *A_ind = lp->A_ind;
double *A_val = lp->A_val;
double *b = lp->b;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int i, j, k, kk, ptr, end;
double dir, delta;
/* working LP is always minimization */
switch (P->dir)
{ case GLP_MIN:
dir = +1.0;
break;
case GLP_MAX:
dir = -1.0;
break;
default:
xassert(P != P);
}
/* initialize constant term of the objective */
c[0] = dir * P->c0;
k = 0; /* number of variable in working LP */
ptr = 1; /* current available position in A_ind/A_val */
/* process rows of original LP */
xassert(P->m == m);
for (i = 1; i <= m; i++)
{ GLPROW *row = P->row[i];
if (excl && row->stat == GLP_NS)
{ /* i-th auxiliary variable is non-basic and fixed */
/* substitute its scaled value in working LP */
xassert(row->type == GLP_FX);
map[i] = 0;
b[i] = - row->lb * row->rii;
}
else
{ /* include i-th auxiliary variable in working LP */
map[i] = ++k;
/* setup k-th column of working constraint matrix which is
* i-th column of unity matrix */
A_ptr[k] = ptr;
A_ind[ptr] = i;
A_val[ptr] = 1.0;
ptr++;
/* initialize right-hand side of i-th equality constraint
* and setup zero objective coefficient at variable x[k] */
b[i] = c[k] = 0.0;
/* setup scaled bounds of variable x[k] */
switch (row->type)
{ case GLP_FR:
l[k] = -DBL_MAX, u[k] = +DBL_MAX;
break;
case GLP_LO:
l[k] = row->lb * row->rii, u[k] = +DBL_MAX;
break;
case GLP_UP:
l[k] = -DBL_MAX, u[k] = row->ub * row->rii;
break;
case GLP_DB:
l[k] = row->lb * row->rii, u[k] = row->ub * row->rii;
xassert(l[k] != u[k]);
break;
case GLP_FX:
l[k] = u[k] = row->lb * row->rii;
break;
default:
xassert(row != row);
}
}
}
/* process columns of original LP */
for (j = 1; j <= P->n; j++)
{ GLPCOL *col = P->col[j];
GLPAIJ *aij;
if (excl && col->stat == GLP_NS)
{ /* j-th structural variable is non-basic and fixed */
/* substitute its scaled value in working LP */
xassert(col->type == GLP_FX);
map[m+j] = 0;
if (col->lb != 0.0)
{ /* (note that sjj scale factor is cancelled) */
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
b[aij->row->i] +=
(aij->row->rii * aij->val) * col->lb;
c[0] += (dir * col->coef) * col->lb;
}
}
else
{ /* include j-th structural variable in working LP */
map[m+j] = ++k;
/* setup k-th column of working constraint matrix which is
* scaled j-th column of original constraint matrix (-A) */
A_ptr[k] = ptr;
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
{ A_ind[ptr] = aij->row->i;
A_val[ptr] = - aij->row->rii * aij->val * col->sjj;
ptr++;
}
/* setup scaled objective coefficient at variable x[k] */
c[k] = dir * col->coef * col->sjj;
/* setup scaled bounds of variable x[k] */
switch (col->type)
{ case GLP_FR:
l[k] = -DBL_MAX, u[k] = +DBL_MAX;
break;
case GLP_LO:
l[k] = col->lb / col->sjj, u[k] = +DBL_MAX;
break;
case GLP_UP:
l[k] = -DBL_MAX, u[k] = col->ub / col->sjj;
break;
case GLP_DB:
l[k] = col->lb / col->sjj, u[k] = col->ub / col->sjj;
xassert(l[k] != u[k]);
break;
case GLP_FX:
l[k] = u[k] = col->lb / col->sjj;
break;
default:
xassert(col != col);
}
}
}
xassert(k == n);
xassert(ptr == nnz+1);
A_ptr[n+1] = ptr;
/* shift bounds of all variables of working LP (optionally) */
if (shift)
{ for (kk = 1; kk <= m+P->n; kk++)
{ k = map[kk];
if (k == 0)
{ /* corresponding original variable was excluded */
continue;
}
/* shift bounds of variable x[k] */
if (l[k] == -DBL_MAX && u[k] == +DBL_MAX)
{ /* x[k] is unbounded variable */
delta = 0.0;
}
else if (l[k] != -DBL_MAX && u[k] == +DBL_MAX)
{ /* shift lower bound to zero */
delta = l[k];
l[k] = 0.0;
}
else if (l[k] == -DBL_MAX && u[k] != +DBL_MAX)
{ /* shift upper bound to zero */
map[kk] = -k;
delta = u[k];
u[k] = 0.0;
}
else if (l[k] != u[k])
{ /* x[k] is double bounded variable */
if (fabs(l[k]) <= fabs(u[k]))
{ /* shift lower bound to zero */
delta = l[k];
l[k] = 0.0, u[k] -= delta;
}
else
{ /* shift upper bound to zero */
map[kk] = -k;
delta = u[k];
l[k] -= delta, u[k] = 0.0;
}
xassert(l[k] != u[k]);
}
else
{ /* shift fixed value to zero */
delta = l[k];
l[k] = u[k] = 0.0;
}
/* substitute x[k] = x'[k] + delta into all constraints
* and the objective function of working LP */
if (delta != 0.0)
{ ptr = A_ptr[k];
end = A_ptr[k+1];
for (; ptr < end; ptr++)
b[A_ind[ptr]] -= A_val[ptr] * delta;
c[0] += c[k] * delta;
}
}
}
return;
}
/***********************************************************************
* spx_build_basis - convert original LP basis to working LP basis
*
* This routine converts the current basis of the original LP to
* corresponding initial basis of the working LP, and moves the basis
* factorization driver from the original LP object to the working LP
* object.
*
* The array map should contain information provided by the routine
* spx_build_lp. */
void spx_build_basis(SPXLP *lp, glp_prob *P, const int map[])
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *flag = lp->flag;
int i, j, k, ii, jj;
/* original basis factorization should be valid that guarantees
* the basis is correct */
xassert(P->m == m);
xassert(P->valid);
/* initialize basis header for working LP */
memset(&head[1], 0, m * sizeof(int));
jj = 0;
/* scan rows of original LP */
xassert(P->m == m);
for (i = 1; i <= m; i++)
{ GLPROW *row = P->row[i];
/* determine ordinal number of x[k] in working LP */
if ((k = map[i]) < 0)
k = -k;
if (k == 0)
{ /* corresponding original variable was excluded */
continue;
}
xassert(1 <= k && k <= n);
if (row->stat == GLP_BS)
{ /* x[k] is basic variable xB[ii] */
ii = row->bind;
xassert(1 <= ii && ii <= m);
xassert(head[ii] == 0);
head[ii] = k;
}
else
{ /* x[k] is non-basic variable xN[jj] */
jj++;
head[m+jj] = k;
flag[jj] = (row->stat == GLP_NU);
}
}
/* scan columns of original LP */
for (j = 1; j <= P->n; j++)
{ GLPCOL *col = P->col[j];
/* determine ordinal number of x[k] in working LP */
if ((k = map[m+j]) < 0)
k = -k;
if (k == 0)
{ /* corresponding original variable was excluded */
continue;
}
xassert(1 <= k && k <= n);
if (col->stat == GLP_BS)
{ /* x[k] is basic variable xB[ii] */
ii = col->bind;
xassert(1 <= ii && ii <= m);
xassert(head[ii] == 0);
head[ii] = k;
}
else
{ /* x[k] is non-basic variable xN[jj] */
jj++;
head[m+jj] = k;
flag[jj] = (col->stat == GLP_NU);
}
}
xassert(m+jj == n);
/* acquire basis factorization */
lp->valid = 1;
lp->bfd = P->bfd;
P->valid = 0;
P->bfd = NULL;
return;
}
/***********************************************************************
* spx_store_basis - convert working LP basis to original LP basis
*
* This routine converts the current working LP basis to corresponding
* original LP basis. This operations includes determining and setting
* statuses of all rows (auxiliary variables) and columns (structural
* variables), and building the basis header.
*
* The array map should contain information provided by the routine
* spx_build_lp.
*
* On exit the routine fills the array daeh. This array should have
* 1+lp->n locations (location [0] is not used) and contain the inverse
* of the working basis header lp->head, i.e. head[k'] = k means that
* daeh[k] = k'. */
void spx_store_basis(SPXLP *lp, glp_prob *P, const int map[],
int daeh[/*1+n*/])
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *flag = lp->flag;
int i, j, k, kk;
/* determine inverse of working basis header */
for (kk = 1; kk <= n; kk++)
daeh[head[kk]] = kk;
/* set row statuses */
xassert(P->m == m);
for (i = 1; i <= m; i++)
{ GLPROW *row = P->row[i];
if ((k = map[i]) < 0)
k = -k;
if (k == 0)
{ /* non-basic fixed auxiliary variable was excluded */
xassert(row->type == GLP_FX);
row->stat = GLP_NS;
row->bind = 0;
}
else
{ /* auxiliary variable corresponds to variable x[k] */
kk = daeh[k];
if (kk <= m)
{ /* x[k] = xB[kk] */
P->head[kk] = i;
row->stat = GLP_BS;
row->bind = kk;
}
else
{ /* x[k] = xN[kk-m] */
switch (row->type)
{ case GLP_FR:
row->stat = GLP_NF;
break;
case GLP_LO:
row->stat = GLP_NL;
break;
case GLP_UP:
row->stat = GLP_NU;
break;
case GLP_DB:
row->stat = (flag[kk-m] ? GLP_NU : GLP_NL);
break;
case GLP_FX:
row->stat = GLP_NS;
break;
default:
xassert(row != row);
}
row->bind = 0;
}
}
}
/* set column statuses */
for (j = 1; j <= P->n; j++)
{ GLPCOL *col = P->col[j];
if ((k = map[m+j]) < 0)
k = -k;
if (k == 0)
{ /* non-basic fixed structural variable was excluded */
xassert(col->type == GLP_FX);
col->stat = GLP_NS;
col->bind = 0;
}
else
{ /* structural variable corresponds to variable x[k] */
kk = daeh[k];
if (kk <= m)
{ /* x[k] = xB[kk] */
P->head[kk] = m+j;
col->stat = GLP_BS;
col->bind = kk;
}
else
{ /* x[k] = xN[kk-m] */
switch (col->type)
{ case GLP_FR:
col->stat = GLP_NF;
break;
case GLP_LO:
col->stat = GLP_NL;
break;
case GLP_UP:
col->stat = GLP_NU;
break;
case GLP_DB:
col->stat = (flag[kk-m] ? GLP_NU : GLP_NL);
break;
case GLP_FX:
col->stat = GLP_NS;
break;
default:
xassert(col != col);
}
col->bind = 0;
}
}
}
return;
}
/***********************************************************************
* spx_store_sol - convert working LP solution to original LP solution
*
* This routine converts the current basic solution of the working LP
* (values of basic variables, simplex multipliers, reduced costs of
* non-basic variables) to corresponding basic solution of the original
* LP (values and reduced costs of auxiliary and structural variables).
* This conversion includes unscaling all basic solution components,
* computing reduced costs of excluded non-basic variables, recovering
* unshifted values of basic variables, changing the signs of reduced
* costs (if the original LP is maximization), and computing the value
* of the objective function.
*
* The flag shift should have the same value as it has in a call to the
* routine spx_build_lp.
*
* The array map should contain information provided by the routine
* spx_build_lp.
*
* The array daeh should contain information provided by the routine
* spx_store_basis.
*
* The arrays beta, pi, and d should contain basic solution components
* for the working LP:
*
* array locations beta[1], ..., beta[m] should contain values of basic
* variables beta = (beta[i]);
*
* array locations pi[1], ..., pi[m] should contain simplex multipliers
* pi = (pi[i]);
*
* array locations d[1], ..., d[n-m] should contain reduced costs of
* non-basic variables d = (d[j]). */
void spx_store_sol(SPXLP *lp, glp_prob *P, int shift,
const int map[], const int daeh[], const double beta[],
const double pi[], const double d[])
{ int m = lp->m;
char *flag = lp->flag;
int i, j, k, kk;
double dir;
/* working LP is always minimization */
switch (P->dir)
{ case GLP_MIN:
dir = +1.0;
break;
case GLP_MAX:
dir = -1.0;
break;
default:
xassert(P != P);
}
/* compute row solution components */
xassert(P->m == m);
for (i = 1; i <= m; i++)
{ GLPROW *row = P->row[i];
if ((k = map[i]) < 0)
k = -k;
if (k == 0)
{ /* non-basic fixed auxiliary variable was excluded */
xassert(row->type == GLP_FX);
row->prim = row->lb;
/* compute reduced cost d[k] = c[k] - A'[k] * pi as if x[k]
* would be non-basic in working LP */
row->dual = - dir * pi[i] * row->rii;
}
else
{ /* auxiliary variable corresponds to variable x[k] */
kk = daeh[k];
if (kk <= m)
{ /* x[k] = xB[kk] */
row->prim = beta[kk] / row->rii;
if (shift)
row->prim += (map[i] < 0 ? row->ub : row->lb);
row->dual = 0.0;
}
else
{ /* x[k] = xN[kk-m] */
row->prim = (flag[kk-m] ? row->ub : row->lb);
row->dual = (dir * d[kk-m]) * row->rii;
}
}
}
/* compute column solution components and objective value */
P->obj_val = P->c0;
for (j = 1; j <= P->n; j++)
{ GLPCOL *col = P->col[j];
if ((k = map[m+j]) < 0)
k = -k;
if (k == 0)
{ /* non-basic fixed structural variable was excluded */
GLPAIJ *aij;
double dk;
xassert(col->type == GLP_FX);
col->prim = col->lb;
/* compute reduced cost d[k] = c[k] - A'[k] * pi as if x[k]
* would be non-basic in working LP */
/* (note that sjj scale factor is cancelled) */
dk = dir * col->coef;
for (aij = col->ptr; aij != NULL; aij = aij->c_next)
dk += (aij->row->rii * aij->val) * pi[aij->row->i];
col->dual = dir * dk;
}
else
{ /* structural variable corresponds to variable x[k] */
kk = daeh[k];
if (kk <= m)
{ /* x[k] = xB[kk] */
col->prim = beta[kk] * col->sjj;
if (shift)
col->prim += (map[m+j] < 0 ? col->ub : col->lb);
col->dual = 0.0;
}
else
{ /* x[k] = xN[kk-m] */
col->prim = (flag[kk-m] ? col->ub : col->lb);
col->dual = (dir * d[kk-m]) / col->sjj;
}
}
P->obj_val += col->coef * col->prim;
}
return;
}
/***********************************************************************
* spx_free_lp - deallocate working LP arrays
*
* This routine deallocates the memory used for arrays of the working
* LP object. */
void spx_free_lp(SPXLP *lp)
{ tfree(lp->A_ptr);
tfree(lp->A_ind);
tfree(lp->A_val);
tfree(lp->b);
tfree(lp->c);
tfree(lp->l);
tfree(lp->u);
tfree(lp->head);
tfree(lp->flag);
return;
}
/* eof */
+62
View File
@@ -0,0 +1,62 @@
/* spxprob.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPXPROB_H
#define SPXPROB_H
#include "prob.h"
#include "spxlp.h"
#define spx_init_lp _glp_spx_init_lp
void spx_init_lp(SPXLP *lp, glp_prob *P, int excl);
/* initialize working LP object */
#define spx_alloc_lp _glp_spx_alloc_lp
void spx_alloc_lp(SPXLP *lp);
/* allocate working LP arrays */
#define spx_build_lp _glp_spx_build_lp
void spx_build_lp(SPXLP *lp, glp_prob *P, int excl, int shift,
int map[/*1+P->m+P->n*/]);
/* convert original LP to working LP */
#define spx_build_basis _glp_spx_build_basis
void spx_build_basis(SPXLP *lp, glp_prob *P, const int map[]);
/* convert original LP basis to working LP basis */
#define spx_store_basis _glp_spx_store_basis
void spx_store_basis(SPXLP *lp, glp_prob *P, const int map[],
int daeh[/*1+n*/]);
/* convert working LP basis to original LP basis */
#define spx_store_sol _glp_spx_store_sol
void spx_store_sol(SPXLP *lp, glp_prob *P, int shift,
const int map[], const int daeh[], const double beta[],
const double pi[], const double d[]);
/* convert working LP solution to original LP solution */
#define spx_free_lp _glp_spx_free_lp
void spx_free_lp(SPXLP *lp);
/* deallocate working LP arrays */
#endif
/* eof */
+565
View File
@@ -0,0 +1,565 @@
/* spychuzc.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015-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 "spychuzc.h"
/***********************************************************************
* spy_chuzc_std - choose non-basic variable (dual textbook ratio test)
*
* This routine implements an improved dual textbook ratio test to
* choose non-basic variable xN[q].
*
* Current reduced costs of non-basic variables should be placed in the
* array locations d[1], ..., d[n-m]. Note that d[j] is a value of dual
* basic variable lambdaN[j] in the current basis.
*
#if 0 (* 14/III-2016 *)
* The parameter s specifies the sign of bound violation for basic
* variable xB[p] chosen: s = +1.0 means that xB[p] violates its lower
* bound, so dual non-basic variable lambdaB[p] = lambda^+B[p]
* increases, and s = -1.0 means that xB[p] violates its upper bound,
* so dual non-basic variable lambdaB[p] = lambda^-B[p] decreases.
* (Thus, the dual ray parameter theta = s * lambdaB[p] >= 0.)
#else
* The parameter r specifies the bound violation for basic variable
* xB[p] chosen:
*
* r = lB[p] - beta[p] > 0 means that xB[p] violates its lower bound,
* so dual non-basic variable lambdaB[p] = lambda^+B[p] increases; and
*
* r = uB[p] - beta[p] < 0 means that xB[p] violates its upper bound,
* so dual non-basic variable lambdaB[p] = lambda^-B[p] decreases.
*
* (Note that r is the dual reduced cost of lambdaB[p].)
#endif
*
* Elements of p-th simplex table row t[p] = (t[p,j]) corresponding
* to basic variable xB[p] should be placed in the array locations
* trow[1], ..., trow[n-m].
*
* The parameter tol_piv specifies a tolerance for elements of the
* simplex table row t[p]. If |t[p,j]| < tol_piv, dual basic variable
* lambdaN[j] is skipped, i.e. it is assumed that it does not depend on
* the dual ray parameter theta.
*
* The parameters tol and tol1 specify tolerances used to increase the
* choice freedom by simulating an artificial degeneracy as follows.
* If lambdaN[j] = lambda^+N[j] >= 0 and d[j] <= +delta[j], or if
* lambdaN[j] = lambda^-N[j] <= 0 and d[j] >= -delta[j], where
* delta[j] = tol + tol1 * |cN[j]|, cN[j] is objective coefficient at
* xN[j], then it is assumed that reduced cost d[j] is equal to zero.
*
* The routine determines the index 1 <= q <= n-m of non-basic variable
* xN[q], for which corresponding dual basic variable lambda^+N[j] or
* lambda^-N[j] reaches its zero bound first on increasing the dual ray
* parameter theta, and returns p on exit. And if theta may increase
* unlimitedly, the routine returns zero. */
int spy_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/],
#if 0 /* 14/III-2016 */
double s, const double trow[/*1+n-m*/], double tol_piv,
#else
double r, const double trow[/*1+n-m*/], double tol_piv,
#endif
double tol, double tol1)
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, k, q;
double alfa, biga, delta, teta, teta_min;
#if 0 /* 14/III-2016 */
xassert(s == +1.0 || s == -1.0);
#else
double s;
xassert(r != 0.0);
s = (r > 0.0 ? +1.0 : -1.0);
#endif
/* nothing is chosen so far */
q = 0, teta_min = DBL_MAX, biga = 0.0;
/* walk thru the list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* if xN[j] is fixed variable, skip it */
if (l[k] == u[k])
continue;
alfa = s * trow[j];
if (alfa >= +tol_piv && !flag[j])
{ /* xN[j] is either free or has its lower bound active, so
* lambdaN[j] = d[j] >= 0 decreases down to zero */
delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
/* determine theta on which lambdaN[j] reaches zero */
teta = (d[j] < +delta ? 0.0 : d[j] / alfa);
}
else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
{ /* xN[j] is either free or has its upper bound active, so
* lambdaN[j] = d[j] <= 0 increases up to zero */
delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
/* determine theta on which lambdaN[j] reaches zero */
teta = (d[j] > -delta ? 0.0 : d[j] / alfa);
}
else
{ /* lambdaN[j] cannot reach zero on increasing theta */
continue;
}
/* choose non-basic variable xN[q] by corresponding dual basic
* variable lambdaN[q] for which theta is minimal */
xassert(teta >= 0.0);
alfa = (alfa >= 0.0 ? +alfa : -alfa);
if (teta_min > teta || (teta_min == teta && biga < alfa))
q = j, teta_min = teta, biga = alfa;
}
return q;
}
/***********************************************************************
* spy_chuzc_harris - choose non-basic var. (dual Harris' ratio test)
*
* This routine implements dual Harris' ratio test to choose non-basic
* variable xN[q].
*
* All the parameters, except tol and tol1, as well as the returned
* value have the same meaning as for the routine spx_chuzr_std (see
* above).
*
* The parameters tol and tol1 specify tolerances on zero bound
* violations for reduced costs of non-basic variables. For reduced
* cost d[j] the tolerance is delta[j] = tol + tol1 |cN[j]|, where
* cN[j] is objective coefficient at non-basic variable xN[j]. */
int spy_chuzc_harris(SPXLP *lp, const double d[/*1+n-m*/],
#if 0 /* 14/III-2016 */
double s, const double trow[/*1+n-m*/], double tol_piv,
#else
double r, const double trow[/*1+n-m*/], double tol_piv,
#endif
double tol, double tol1)
{ int m = lp->m;
int n = lp->n;
double *c = lp->c;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, k, q;
double alfa, biga, delta, teta, teta_min;
#if 0 /* 14/III-2016 */
xassert(s == +1.0 || s == -1.0);
#else
double s;
xassert(r != 0.0);
s = (r > 0.0 ? +1.0 : -1.0);
#endif
/*--------------------------------------------------------------*/
/* first pass: determine teta_min for relaxed bounds */
/*--------------------------------------------------------------*/
teta_min = DBL_MAX;
/* walk thru the list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* if xN[j] is fixed variable, skip it */
if (l[k] == u[k])
continue;
alfa = s * trow[j];
if (alfa >= +tol_piv && !flag[j])
{ /* xN[j] is either free or has its lower bound active, so
* lambdaN[j] = d[j] >= 0 decreases down to zero */
delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
/* determine theta on which lambdaN[j] reaches -delta */
teta = ((d[j] < 0.0 ? 0.0 : d[j]) + delta) / alfa;
}
else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
{ /* xN[j] is either free or has its upper bound active, so
* lambdaN[j] = d[j] <= 0 increases up to zero */
delta = tol + tol1 * (c[k] >= 0.0 ? +c[k] : -c[k]);
/* determine theta on which lambdaN[j] reaches +delta */
teta = ((d[j] > 0.0 ? 0.0 : d[j]) - delta) / alfa;
}
else
{ /* lambdaN[j] cannot reach zero on increasing theta */
continue;
}
xassert(teta >= 0.0);
if (teta_min > teta)
teta_min = teta;
}
/*--------------------------------------------------------------*/
/* second pass: choose non-basic variable xN[q] */
/*--------------------------------------------------------------*/
if (teta_min == DBL_MAX)
{ /* theta may increase unlimitedly */
q = 0;
goto done;
}
/* nothing is chosen so far */
q = 0, biga = 0.0;
/* walk thru the list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* if xN[j] is fixed variable, skip it */
if (l[k] == u[k])
continue;
alfa = s * trow[j];
if (alfa >= +tol_piv && !flag[j])
{ /* xN[j] is either free or has its lower bound active, so
* lambdaN[j] = d[j] >= 0 decreases down to zero */
/* determine theta on which lambdaN[j] reaches zero */
teta = d[j] / alfa;
}
else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
{ /* xN[j] is either free or has its upper bound active, so
* lambdaN[j] = d[j] <= 0 increases up to zero */
/* determine theta on which lambdaN[j] reaches zero */
teta = d[j] / alfa;
}
else
{ /* lambdaN[j] cannot reach zero on increasing theta */
continue;
}
/* choose non-basic variable for which theta is not greater
* than theta_min determined for relaxed bounds and which has
* best (largest in magnitude) pivot */
alfa = (alfa >= 0.0 ? +alfa : -alfa);
if (teta <= teta_min && biga < alfa)
q = j, biga = alfa;
}
/* something must be chosen */
xassert(1 <= q && q <= n-m);
done: return q;
}
#if 0 /* 23/III-2016 */
/***********************************************************************
* spy_eval_bp - determine dual objective function break-points
*
* This routine determines the dual objective function break-points.
*
* The parameters lp, d, r, trow, and tol_piv have the same meaning as
* for the routine spx_chuzc_std (see above).
*
* On exit the routine stores the break-points determined to the array
* elements bp[1], ..., bp[num], where 0 <= num <= n-m is the number of
* break-points returned by the routine.
*
* The break-points stored in the array bp are ordered by ascending
* the ray parameter teta >= 0. The break-points numbered 1, ..., num-1
* always correspond to non-basic non-fixed variables xN[j] of primal
* LP having both lower and upper bounds while the last break-point
* numbered num may correspond to a non-basic variable having only one
* lower or upper bound, if such variable prevents further increasing
* of the ray parameter teta. Besides, the routine includes in the
* array bp only the break-points that correspond to positive increment
* of the dual objective. */
static int CDECL fcmp(const void *v1, const void *v2)
{ const SPYBP *p1 = v1, *p2 = v2;
if (p1->teta < p2->teta)
return -1;
else if (p1->teta > p2->teta)
return +1;
else
return 0;
}
int spy_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
double r, const double trow[/*1+n-m*/], double tol_piv,
SPYBP bp[/*1+n-m*/])
{ int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, j_max, k, t, nnn, num;
double s, alfa, teta, teta_max, dz, v;
xassert(r != 0.0);
s = (r > 0.0 ? +1.0 : -1.0);
/* build the list of all dual basic variables lambdaN[j] that
* can reach zero on increasing the ray parameter teta >= 0 */
num = 0;
/* walk thru the list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* if xN[j] is fixed variable, skip it */
if (l[k] == u[k])
continue;
alfa = s * trow[j];
if (alfa >= +tol_piv && !flag[j])
{ /* xN[j] is either free or has its lower bound active, so
* lambdaN[j] = d[j] >= 0 decreases down to zero */
/* determine teta[j] on which lambdaN[j] reaches zero */
teta = (d[j] < 0.0 ? 0.0 : d[j] / alfa);
}
else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
{ /* xN[j] is either free or has its upper bound active, so
* lambdaN[j] = d[j] <= 0 increases up to zero */
/* determine teta[j] on which lambdaN[j] reaches zero */
teta = (d[j] > 0.0 ? 0.0 : d[j] / alfa);
}
else
{ /* lambdaN[j] cannot reach zero on increasing teta */
continue;
}
/* add lambdaN[j] to the list */
num++;
bp[num].j = j;
bp[num].teta = teta;
}
if (num == 0)
{ /* dual unboundedness */
goto done;
}
/* determine "blocking" dual basic variable lambdaN[j_max] that
* prevents increasing teta more than teta_max */
j_max = 0, teta_max = DBL_MAX;
for (t = 1; t <= num; t++)
{ j = bp[t].j;
k = head[m+j]; /* x[k] = xN[j] */
if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
{ /* lambdaN[j] cannot intersect zero */
if (j_max == 0
|| teta_max > bp[t].teta
|| (teta_max == bp[t].teta
&& fabs(trow[j_max]) < fabs(trow[j])))
j_max = j, teta_max = bp[t].teta;
}
}
/* keep in the list only dual basic variables lambdaN[j] that
* correspond to primal double-bounded variables xN[j] and whose
* teta[j] is not greater than teta_max */
nnn = 0;
for (t = 1; t <= num; t++)
{ j = bp[t].j;
k = head[m+j]; /* x[k] = xN[j] */
if (l[k] != -DBL_MAX && u[k] != +DBL_MAX
&& bp[t].teta <= teta_max)
{ nnn++;
bp[nnn].j = j;
bp[nnn].teta = bp[t].teta;
}
}
num = nnn;
/* sort break-points by ascending teta[j] */
qsort(&bp[1], num, sizeof(SPYBP), fcmp);
/* add lambdaN[j_max] to the end of the list */
if (j_max != 0)
{ xassert(num < n-m);
num++;
bp[num].j = j_max;
bp[num].teta = teta_max;
}
/* compute increments of the dual objective at all break-points
* (relative to its value at teta = 0) */
dz = 0.0; /* dual objective increment */
v = fabs(r); /* dual objective slope d zeta / d teta */
for (t = 1; t <= num; t++)
{ /* compute increment at current break-point */
dz += v * (bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
if (dz < 0.001)
{ /* break-point with non-positive increment reached */
num = t - 1;
break;
}
bp[t].dz = dz;
/* compute next slope on the right to current break-point */
if (t < num)
{ j = bp[t].j;
k = head[m+j]; /* x[k] = xN[j] */
xassert(-DBL_MAX < l[k] && l[k] < u[k] && u[k] < +DBL_MAX);
v -= fabs(trow[j]) * (u[k] - l[k]);
}
}
done: return num;
}
#endif
/***********************************************************************
* spy_ls_eval_bp - determine dual objective function break-points
*
* This routine determines the dual objective function break-points.
*
* The parameters lp, d, r, trow, and tol_piv have the same meaning as
* for the routine spx_chuzc_std (see above).
*
* The routine stores the break-points determined to the array elements
* bp[1], ..., bp[nbp] in *arbitrary* order, where 0 <= nbp <= n-m is
* the number of break-points returned by the routine on exit. */
int spy_ls_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
double r, const double trow[/*1+n-m*/], double tol_piv,
SPYBP bp[/*1+n-m*/])
{ int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
char *flag = lp->flag;
int j, k, t, nnn, nbp;
double s, alfa, teta, teta_max;
xassert(r != 0.0);
s = (r > 0.0 ? +1.0 : -1.0);
/* build the list of all dual basic variables lambdaN[j] that
* can reach zero on increasing the ray parameter teta >= 0 */
nnn = 0, teta_max = DBL_MAX;
/* walk thru the list of non-basic variables */
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
/* if xN[j] is fixed variable, skip it */
if (l[k] == u[k])
continue;
alfa = s * trow[j];
if (alfa >= +tol_piv && !flag[j])
{ /* xN[j] is either free or has its lower bound active, so
* lambdaN[j] = d[j] >= 0 decreases down to zero */
/* determine teta[j] on which lambdaN[j] reaches zero */
teta = (d[j] < 0.0 ? 0.0 : d[j] / alfa);
/* if xN[j] has no upper bound, lambdaN[j] cannot become
* negative and thereby blocks further increasing teta */
if (u[k] == +DBL_MAX && teta_max > teta)
teta_max = teta;
}
else if (alfa <= -tol_piv && (l[k] == -DBL_MAX || flag[j]))
{ /* xN[j] is either free or has its upper bound active, so
* lambdaN[j] = d[j] <= 0 increases up to zero */
/* determine teta[j] on which lambdaN[j] reaches zero */
teta = (d[j] > 0.0 ? 0.0 : d[j] / alfa);
/* if xN[j] has no lower bound, lambdaN[j] cannot become
* positive and thereby blocks further increasing teta */
if (l[k] == -DBL_MAX && teta_max > teta)
teta_max = teta;
}
else
{ /* lambdaN[j] cannot reach zero on increasing teta */
continue;
}
/* add lambdaN[j] to the list */
nnn++;
bp[nnn].j = j;
bp[nnn].teta = teta;
}
/* remove from the list all dual basic variables lambdaN[j], for
* which teta[j] > teta_max */
nbp = 0;
for (t = 1; t <= nnn; t++)
{ if (bp[t].teta <= teta_max + 1e-6)
{ nbp++;
bp[nbp].j = bp[t].j;
bp[nbp].teta = bp[t].teta;
}
}
return nbp;
}
/***********************************************************************
* spy_ls_select_bp - select and process dual objective break-points
*
* This routine selects a next portion of the dual objective function
* break-points and processes them.
*
* On entry to the routine it is assumed that break-points bp[1], ...,
* bp[num] are already processed, and slope is the dual objective slope
* to the right of the last processed break-point bp[num]. (Initially,
* when num = 0, slope should be specified as fabs(r), where r has the
* same meaning as above.)
*
* The routine selects break-points among bp[num+1], ..., bp[nbp], for
* which teta <= teta_lim, and moves these break-points to the array
* elements bp[num+1], ..., bp[num1], where num <= num1 <= n-m is the
* new number of processed break-points returned by the routine on
* exit. Then the routine sorts these break-points by ascending teta
* and computes the change of the dual objective function relative to
* its value at teta = 0.
*
* On exit the routine also replaces the parameter slope with a new
* value that corresponds to the new last break-point bp[num1]. */
static int CDECL fcmp(const void *v1, const void *v2)
{ const SPYBP *p1 = v1, *p2 = v2;
if (p1->teta < p2->teta)
return -1;
else if (p1->teta > p2->teta)
return +1;
else
return 0;
}
int spy_ls_select_bp(SPXLP *lp, const double trow[/*1+n-m*/],
int nbp, SPYBP bp[/*1+n-m*/], int num, double *slope, double
teta_lim)
{ int m = lp->m;
int n = lp->n;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int j, k, t, num1;
double teta, dz;
xassert(0 <= num && num <= nbp && nbp <= n-m);
/* select a new portion of break-points */
num1 = num;
for (t = num+1; t <= nbp; t++)
{ if (bp[t].teta <= teta_lim)
{ /* move break-point to the beginning of the new portion */
num1++;
j = bp[num1].j, teta = bp[num1].teta;
bp[num1].j = bp[t].j, bp[num1].teta = bp[t].teta;
bp[t].j = j, bp[t].teta = teta;
}
}
/* sort new break-points bp[num+1], ..., bp[num1] by ascending
* the ray parameter teta */
if (num1 - num > 1)
qsort(&bp[num+1], num1 - num, sizeof(SPYBP), fcmp);
/* calculate the dual objective change at the new break-points */
for (t = num+1; t <= num1; t++)
{ /* calculate the dual objective change relative to its value
* at break-point bp[t-1] */
if (*slope == -DBL_MAX)
dz = -DBL_MAX;
else
dz = (*slope) *
(bp[t].teta - (t == 1 ? 0.0 : bp[t-1].teta));
/* calculate the dual objective change relative to its value
* at teta = 0 */
if (dz == -DBL_MAX)
bp[t].dz = -DBL_MAX;
else
bp[t].dz = (t == 1 ? 0.0 : bp[t-1].dz) + dz;
/* calculate a new slope of the dual objective to the right of
* the current break-point bp[t] */
if (*slope != -DBL_MAX)
{ j = bp[t].j;
k = head[m+j]; /* x[k] = xN[j] */
if (l[k] == -DBL_MAX || u[k] == +DBL_MAX)
*slope = -DBL_MAX; /* blocking break-point reached */
else
{ xassert(l[k] < u[k]);
*slope -= fabs(trow[j]) * (u[k] - l[k]);
}
}
}
return num1;
}
/* eof */
+83
View File
@@ -0,0 +1,83 @@
/* spychuzc.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015-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/>.
***********************************************************************/
#ifndef SPYCHUZC_H
#define SPYCHUZC_H
#include "spxlp.h"
#define spy_chuzc_std _glp_spy_chuzc_std
int spy_chuzc_std(SPXLP *lp, const double d[/*1+n-m*/],
#if 0 /* 14/III-2016 */
double s, const double trow[/*1+n-m*/], double tol_piv,
#else
double r, const double trow[/*1+n-m*/], double tol_piv,
#endif
double tol, double tol1);
/* choose non-basic variable (dual textbook ratio test) */
#define spy_chuzc_harris _glp_spy_chuzc_harris
int spy_chuzc_harris(SPXLP *lp, const double d[/*1+n-m*/],
#if 0 /* 14/III-2016 */
double s, const double trow[/*1+n-m*/], double tol_piv,
#else
double r, const double trow[/*1+n-m*/], double tol_piv,
#endif
double tol, double tol1);
/* choose non-basic variable (dual Harris' ratio test) */
typedef struct SPYBP SPYBP;
struct SPYBP
{ /* dual objective function break point */
int j;
/* dual basic variable lambdaN[j], 1 <= j <= n-m, that intersects
* zero at this break point */
double teta;
/* ray parameter value, teta[j] >= 0, at this break point */
double dz;
/* increment, zeta[j] - zeta[0], of the dual objective function
* at this break point */
};
#if 0 /* 23/III-2016 */
#define spy_eval_bp _glp_spy_eval_bp
int spy_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
double r, const double trow[/*1+n-m*/], double tol_piv,
SPYBP bp[/*1+n-m*/]);
/* determine dual objective function break-points */
#endif
#define spy_ls_eval_bp _glp_spy_ls_eval_bp
int spy_ls_eval_bp(SPXLP *lp, const double d[/*1+n-m*/],
double r, const double trow[/*1+n-m*/], double tol_piv,
SPYBP bp[/*1+n-m*/]);
/* determine dual objective function break-points */
#define spy_ls_select_bp _glp_spy_ls_select_bp
int spy_ls_select_bp(SPXLP *lp, const double trow[/*1+n-m*/],
int nbp, SPYBP bp[/*1+n-m*/], int num, double *slope, double
teta_lim);
/* select and process dual objective break-points */
#endif
/* eof */
+481
View File
@@ -0,0 +1,481 @@
/* spychuzr.c */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 "spychuzr.h"
/***********************************************************************
* spy_chuzr_sel - select eligible basic variables
*
* This routine selects eligible basic variables xB[i], whose value
* beta[i] violates corresponding lower lB[i] or upper uB[i] bound.
* Positive bound violation rp[i] = lb[i] - beta[i] > 0 is the reduced
* cost of non-basic dual variable lambda^+B[i] >= 0, so increasing it
* increases the dual objective. Similarly, negative bound violation
* rn[i] = ub[i] - beta[i] < 0 is the reduced cost of non-basic dual
* variable lambda^-B[i] <= 0, so decreasing it also increases the dual
* objective.
*
* Current values of basic variables should be placed in the array
* locations beta[1], ..., beta[m].
*
* Basic variable xB[i] is considered eligible, if:
*
* beta[i] <= lB[i] - eps1[i], or
*
* beta[i] >= uB[i] + eps2[i],
*
* for
*
* eps1[i] = tol + tol1 * |lB[i]|,
*
* eps2[i] = tol + tol2 * |uB[i]|,
*
* where lB[i] and uB[i] are, resp., lower and upper bounds of xB[i],
* tol and tol1 are specified tolerances.
*
* On exit the routine stores indices i of eligible basic variables
* xB[i] to the array locations list[1], ..., list[num] and returns the
* number of such variables 0 <= num <= m. (If the parameter list is
* specified as NULL, no indices are stored.) */
int spy_chuzr_sel(SPXLP *lp, const double beta[/*1+m*/], double tol,
double tol1, int list[/*1+m*/])
{ int m = lp->m;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int i, k, num;
double lk, uk, eps;
num = 0;
/* walk thru list of basic variables */
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
lk = l[k], uk = u[k];
/* check if xB[i] is eligible */
if (beta[i] < lk)
{ /* determine absolute tolerance eps1[i] */
eps = tol + tol1 * (lk >= 0.0 ? +lk : -lk);
if (beta[i] < lk - eps)
{ /* lower bound is violated */
num++;
if (list != NULL)
list[num] = i;
}
}
else if (beta[i] > uk)
{ /* determine absolute tolerance eps2[i] */
eps = tol + tol1 * (uk >= 0.0 ? +uk : -uk);
if (beta[i] > uk + eps)
{ /* upper bound is violated */
num++;
if (list != NULL)
list[num] = i;
}
}
}
return num;
}
/***********************************************************************
* spy_chuzr_std - choose basic variable (dual Dantzig's rule)
*
* This routine chooses most eligible basic variable xB[p] according
* to dual Dantzig's ("standard") rule:
*
* r[p] = max |r[i]|,
* i in I
*
* ( lB[i] - beta[i], if beta[i] < lB[i]
* (
* r[i] = { 0, if lB[i] <= beta[i] <= uB[i]
* (
* ( uB[i] - beta[i], if beta[i] > uB[i]
*
* where I <= {1, ..., m} is the set of indices of eligible basic
* variables, beta[i] is current value of xB[i], lB[i] and uB[i] are,
* resp., lower and upper bounds of xB[i], r[i] is bound violation.
*
* Current values of basic variables should be placed in the array
* locations beta[1], ..., beta[m].
*
* Indices of eligible basic variables i in I should be placed in the
* array locations list[1], ..., list[num], where num = |J| > 0 is the
* total number of such variables.
*
* On exit the routine returns p, the index of the basic variable xB[p]
* chosen. */
int spy_chuzr_std(SPXLP *lp, const double beta[/*1+m*/], int num,
const int list[])
{ int m = lp->m;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
int i, k, p, t;
double abs_ri, abs_rp;
xassert(0 < num && num <= m);
p = 0, abs_rp = -1.0;
for (t = 1; t <= num; t++)
{ i = list[t];
k = head[i]; /* x[k] = xB[i] */
if (beta[i] < l[k])
abs_ri = l[k] - beta[i];
else if (beta[i] > u[k])
abs_ri = beta[i] - u[k];
else
xassert(t != t);
if (abs_rp < abs_ri)
p = i, abs_rp = abs_ri;
}
xassert(p != 0);
return p;
}
/***********************************************************************
* spy_alloc_se - allocate dual pricing data block
*
* This routine allocates the memory for arrays used in the dual
* pricing data block. */
void spy_alloc_se(SPXLP *lp, SPYSE *se)
{ int m = lp->m;
int n = lp->n;
#if 1 /* 30/III-2016 */
int i;
#endif
se->valid = 0;
se->refsp = talloc(1+n, char);
se->gamma = talloc(1+m, double);
se->work = talloc(1+m, double);
#if 1 /* 30/III-2016 */
se->u.n = m;
se->u.nnz = 0;
se->u.ind = talloc(1+m, int);
se->u.vec = talloc(1+m, double);
for (i = 1; i <= m; i++)
se->u.vec[i] = 0.0;
#endif
return;
}
/***********************************************************************
* spy_reset_refsp - reset dual reference space
*
* This routine resets (re-initializes) the dual reference space
* composing it from dual variables which are non-basic (corresponding
* to basic primal variables) in the current basis, and sets all
* weights gamma[i] to 1. */
void spy_reset_refsp(SPXLP *lp, SPYSE *se)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *gamma = se->gamma;
int i, k;
se->valid = 1;
memset(&refsp[1], 0, n * sizeof(char));
for (i = 1; i <= m; i++)
{ k = head[i]; /* x[k] = xB[i] */
refsp[k] = 1;
gamma[i] = 1.0;
}
return;
}
/***********************************************************************
* spy_eval_gamma_i - compute dual proj. steepest edge weight directly
*
* This routine computes dual projected steepest edge weight gamma[i],
* 1 <= i <= m, for the current basis directly with the formula:
*
* n-m
* gamma[i] = delta[i] + sum eta[j] * T[i,j]**2,
* j=1
*
* where T[i,j] is element of the current simplex table, and
*
* ( 1, if lambdaN[j] is in the reference space
* eta[j] = {
* ( 0, otherwise
*
* ( 1, if lambdaB[i] is in the reference space
* delta[i] = {
* ( 0, otherwise
*
* Dual basic variable lambdaN[j] corresponds to primal non-basic
* variable xN[j], and dual non-basic variable lambdaB[j] corresponds
* to primal basic variable xB[i].
*
* NOTE: For testing/debugging only. */
double spy_eval_gamma_i(SPXLP *lp, SPYSE *se, int i)
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *rho = se->work;
int j, k;
double gamma_i, t_ij;
xassert(se->valid);
xassert(1 <= i && i <= m);
k = head[i]; /* x[k] = xB[i] */
gamma_i = (refsp[k] ? 1.0 : 0.0);
spx_eval_rho(lp, i, rho);
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
if (refsp[k])
{ t_ij = spx_eval_tij(lp, rho, j);
gamma_i += t_ij * t_ij;
}
}
return gamma_i;
}
/***********************************************************************
* spy_chuzr_pse - choose basic variable (dual projected steepest edge)
*
* This routine chooses most eligible basic variable xB[p] according
* to the dual projected steepest edge method:
*
* r[p]**2 r[i]**2
* -------- = max -------- ,
* gamma[p] i in I gamma[i]
*
* ( lB[i] - beta[i], if beta[i] < lB[i]
* (
* r[i] = { 0, if lB[i] <= beta[i] <= uB[i]
* (
* ( uB[i] - beta[i], if beta[i] > uB[i]
*
* where I <= {1, ..., m} is the set of indices of eligible basic
* variables, beta[i] is current value of xB[i], lB[i] and uB[i] are,
* resp., lower and upper bounds of xB[i], r[i] is bound violation.
*
* Current values of basic variables should be placed in the array
* locations beta[1], ..., beta[m].
*
* Indices of eligible basic variables i in I should be placed in the
* array locations list[1], ..., list[num], where num = |J| > 0 is the
* total number of such variables.
*
* On exit the routine returns p, the index of the basic variable xB[p]
* chosen. */
int spy_chuzr_pse(SPXLP *lp, SPYSE *se, const double beta[/*1+m*/],
int num, const int list[])
{ int m = lp->m;
double *l = lp->l;
double *u = lp->u;
int *head = lp->head;
double *gamma = se->gamma;
int i, k, p, t;
double best, ri, temp;
xassert(0 < num && num <= m);
p = 0, best = -1.0;
for (t = 1; t <= num; t++)
{ i = list[t];
k = head[i]; /* x[k] = xB[i] */
if (beta[i] < l[k])
ri = l[k] - beta[i];
else if (beta[i] > u[k])
ri = u[k] - beta[i];
else
xassert(t != t);
/* FIXME */
if (gamma[i] < DBL_EPSILON)
temp = 0.0;
else
temp = (ri * ri) / gamma[i];
if (best < temp)
p = i, best = temp;
}
xassert(p != 0);
return p;
}
/***********************************************************************
* spy_update_gamma - update dual proj. steepest edge weights exactly
*
* This routine updates the vector gamma = (gamma[i]) of dual projected
* steepest edge weights exactly, for the adjacent basis.
*
* On entry to the routine the content of the se object should be valid
* and should correspond to the current basis.
*
* The parameter 1 <= p <= m specifies basic variable xB[p] which
* becomes non-basic variable xN[q] in the adjacent basis.
*
* The parameter 1 <= q <= n-m specified non-basic variable xN[q] which
* becomes basic variable xB[p] in the adjacent basis.
*
* It is assumed that the array trow contains elements of p-th (pivot)
* row T'[p] of the simplex table in locations trow[1], ..., trow[n-m].
* It is also assumed that the array tcol contains elements of q-th
* (pivot) column T[q] of the simple table in locations tcol[1], ...,
* tcol[m]. (These row and column should be computed for the current
* basis.)
*
* For details about the formulae used see the program documentation.
*
* The routine also computes the relative error:
*
* e = |gamma[p] - gamma'[p]| / (1 + |gamma[p]|),
*
* where gamma'[p] is the weight for lambdaB[p] (which is dual
* non-basic variable corresponding to xB[p]) on entry to the routine,
* and returns e on exit. (If e happens to be large enough, the calling
* program may reset the reference space, since other weights also may
* be inaccurate.) */
double spy_update_gamma(SPXLP *lp, SPYSE *se, int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/])
{ int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *gamma = se->gamma;
double *u = se->work;
int i, j, k, ptr, end;
double gamma_p, delta_p, e, r, t1, t2;
xassert(se->valid);
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* compute gamma[p] in current basis more accurately; also
* compute auxiliary vector u */
k = head[p]; /* x[k] = xB[p] */
gamma_p = delta_p = (refsp[k] ? 1.0 : 0.0);
for (i = 1; i <= m; i++)
u[i] = 0.0;
for (j = 1; j <= n-m; j++)
{ k = head[m+j]; /* x[k] = xN[j] */
if (refsp[k] && trow[j] != 0.0)
{ gamma_p += trow[j] * trow[j];
/* u := u + T[p,j] * N[j], where N[j] = A[k] is constraint
* matrix column corresponding to xN[j] */
ptr = lp->A_ptr[k];
end = lp->A_ptr[k+1];
for (; ptr < end; ptr++)
u[lp->A_ind[ptr]] += trow[j] * lp->A_val[ptr];
}
}
bfd_ftran(lp->bfd, u);
/* compute relative error in gamma[p] */
e = fabs(gamma_p - gamma[p]) / (1.0 + gamma_p);
/* compute new gamma[p] */
gamma[p] = gamma_p / (tcol[p] * tcol[p]);
/* compute new gamma[i] for all i != p */
for (i = 1; i <= m; i++)
{ if (i == p)
continue;
/* compute r[i] = T[i,q] / T[p,q] */
r = tcol[i] / tcol[p];
/* compute new gamma[i] */
t1 = gamma[i] + r * (r * gamma_p + u[i] + u[i]);
k = head[i]; /* x[k] = xB[i] */
t2 = (refsp[k] ? 1.0 : 0.0) + delta_p * r * r;
gamma[i] = (t1 >= t2 ? t1 : t2);
}
return e;
}
#if 1 /* 30/III-2016 */
double spy_update_gamma_s(SPXLP *lp, SPYSE *se, int p, int q,
const FVS *trow, const FVS *tcol)
{ /* sparse version of spy_update_gamma */
int m = lp->m;
int n = lp->n;
int *head = lp->head;
char *refsp = se->refsp;
double *gamma = se->gamma;
double *u = se->work;
int trow_nnz = trow->nnz;
int *trow_ind = trow->ind;
double *trow_vec = trow->vec;
int tcol_nnz = tcol->nnz;
int *tcol_ind = tcol->ind;
double *tcol_vec = tcol->vec;
int i, j, k, t, ptr, end;
double gamma_p, delta_p, e, r, t1, t2;
xassert(se->valid);
xassert(1 <= p && p <= m);
xassert(1 <= q && q <= n-m);
/* compute gamma[p] in current basis more accurately; also
* compute auxiliary vector u */
k = head[p]; /* x[k] = xB[p] */
gamma_p = delta_p = (refsp[k] ? 1.0 : 0.0);
for (i = 1; i <= m; i++)
u[i] = 0.0;
for (t = 1; t <= trow_nnz; t++)
{ j = trow_ind[t];
k = head[m+j]; /* x[k] = xN[j] */
if (refsp[k])
{ gamma_p += trow_vec[j] * trow_vec[j];
/* u := u + T[p,j] * N[j], where N[j] = A[k] is constraint
* matrix column corresponding to xN[j] */
ptr = lp->A_ptr[k];
end = lp->A_ptr[k+1];
for (; ptr < end; ptr++)
u[lp->A_ind[ptr]] += trow_vec[j] * lp->A_val[ptr];
}
}
bfd_ftran(lp->bfd, u);
/* compute relative error in gamma[p] */
e = fabs(gamma_p - gamma[p]) / (1.0 + gamma_p);
/* compute new gamma[p] */
gamma[p] = gamma_p / (tcol_vec[p] * tcol_vec[p]);
/* compute new gamma[i] for all i != p */
for (t = 1; t <= tcol_nnz; t++)
{ i = tcol_ind[t];
if (i == p)
continue;
/* compute r[i] = T[i,q] / T[p,q] */
r = tcol_vec[i] / tcol_vec[p];
/* compute new gamma[i] */
t1 = gamma[i] + r * (r * gamma_p + u[i] + u[i]);
k = head[i]; /* x[k] = xB[i] */
t2 = (refsp[k] ? 1.0 : 0.0) + delta_p * r * r;
gamma[i] = (t1 >= t2 ? t1 : t2);
}
return e;
}
#endif
/***********************************************************************
* spy_free_se - deallocate dual pricing data block
*
* This routine deallocates the memory used for arrays in the dual
* pricing data block. */
void spy_free_se(SPXLP *lp, SPYSE *se)
{ xassert(lp == lp);
tfree(se->refsp);
tfree(se->gamma);
tfree(se->work);
#if 1 /* 30/III-2016 */
tfree(se->u.ind);
tfree(se->u.vec);
#endif
return;
}
/* eof */
+95
View File
@@ -0,0 +1,95 @@
/* spychuzr.h */
/***********************************************************************
* This code is part of GLPK (GNU Linear Programming Kit).
* Copyright (C) 2015 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 SPYCHUZR_H
#define SPYCHUZR_H
#include "spxlp.h"
#define spy_chuzr_sel _glp_spy_chuzr_sel
int spy_chuzr_sel(SPXLP *lp, const double beta[/*1+m*/], double tol,
double tol1, int list[/*1+m*/]);
/* select eligible basic variables */
#define spy_chuzr_std _glp_spy_chuzr_std
int spy_chuzr_std(SPXLP *lp, const double beta[/*1+m*/], int num,
const int list[]);
/* choose basic variable (dual Dantzig's rule) */
typedef struct SPYSE SPYSE;
struct SPYSE
{ /* dual projected steepest edge and Devex pricing data block */
int valid;
/* content validity flag */
char *refsp; /* char refsp[1+n]; */
/* refsp[0] is not used;
* refsp[k], 1 <= k <= n, is the flag meaning that dual variable
* lambda[k] is in the dual reference space */
double *gamma; /* double gamma[1+m]; */
/* gamma[0] is not used;
* gamma[i], 1 <= i <= m, is the weight for reduced cost r[i]
* of dual non-basic variable lambdaB[j] in the current basis
* (r[i] is bound violation for basic variable xB[i]) */
double *work; /* double work[1+m]; */
/* working array */
#if 1 /* 30/III-2016 */
FVS u; /* FVS u[1:m]; */
/* working vector */
#endif
};
#define spy_alloc_se _glp_spy_alloc_se
void spy_alloc_se(SPXLP *lp, SPYSE *se);
/* allocate dual pricing data block */
#define spy_reset_refsp _glp_spy_reset_refsp
void spy_reset_refsp(SPXLP *lp, SPYSE *se);
/* reset dual reference space */
#define spy_eval_gamma_i _glp_spy_eval_gamma_i
double spy_eval_gamma_i(SPXLP *lp, SPYSE *se, int i);
/* compute dual projected steepest edge weight directly */
#define spy_chuzr_pse _glp_spy_chuzr_pse
int spy_chuzr_pse(SPXLP *lp, SPYSE *se, const double beta[/*1+m*/],
int num, const int list[]);
/* choose basic variable (dual projected steepest edge) */
#define spy_update_gamma _glp_spy_update_gamma
double spy_update_gamma(SPXLP *lp, SPYSE *se, int p, int q,
const double trow[/*1+n-m*/], const double tcol[/*1+m*/]);
/* update dual projected steepest edge weights exactly */
#if 1 /* 30/III-2016 */
#define spy_update_gamma_s _glp_spy_update_gamma_s
double spy_update_gamma_s(SPXLP *lp, SPYSE *se, int p, int q,
const FVS *trow, const FVS *tcol);
/* sparse version of spy_update_gamma */
#endif
#define spy_free_se _glp_spy_free_se
void spy_free_se(SPXLP *lp, SPYSE *se);
/* deallocate dual pricing data block */
#endif
/* eof */
File diff suppressed because it is too large Load Diff