You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
8.6 KiB
265 lines
8.6 KiB
/* spxat.c */
|
|
|
|
/***********************************************************************
|
|
* This code is part of GLPK (GNU Linear Programming Kit).
|
|
*
|
|
* Copyright (C) 2015 Andrew Makhorin, Department for Applied
|
|
* Informatics, Moscow Aviation Institute, Moscow, Russia. All rights
|
|
* reserved. E-mail: <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 */
|