/* 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: . * * 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 . ***********************************************************************/ #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 */