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