lemon-project-template-glpk
diff deps/glpk/src/glpscf.c @ 9:33de93886c88
Import GLPK 4.47
author | Alpar Juttner <alpar@cs.elte.hu> |
---|---|
date | Sun, 06 Nov 2011 20:59:10 +0100 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/deps/glpk/src/glpscf.c Sun Nov 06 20:59:10 2011 +0100 1.3 @@ -0,0 +1,634 @@ 1.4 +/* glpscf.c (Schur complement factorization) */ 1.5 + 1.6 +/*********************************************************************** 1.7 +* This code is part of GLPK (GNU Linear Programming Kit). 1.8 +* 1.9 +* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 1.10 +* 2009, 2010, 2011 Andrew Makhorin, Department for Applied Informatics, 1.11 +* Moscow Aviation Institute, Moscow, Russia. All rights reserved. 1.12 +* E-mail: <mao@gnu.org>. 1.13 +* 1.14 +* GLPK is free software: you can redistribute it and/or modify it 1.15 +* under the terms of the GNU General Public License as published by 1.16 +* the Free Software Foundation, either version 3 of the License, or 1.17 +* (at your option) any later version. 1.18 +* 1.19 +* GLPK is distributed in the hope that it will be useful, but WITHOUT 1.20 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1.21 +* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1.22 +* License for more details. 1.23 +* 1.24 +* You should have received a copy of the GNU General Public License 1.25 +* along with GLPK. If not, see <http://www.gnu.org/licenses/>. 1.26 +***********************************************************************/ 1.27 + 1.28 +#include "glpenv.h" 1.29 +#include "glpscf.h" 1.30 +#define xfault xerror 1.31 + 1.32 +#define _GLPSCF_DEBUG 0 1.33 + 1.34 +#define eps 1e-10 1.35 + 1.36 +/*********************************************************************** 1.37 +* NAME 1.38 +* 1.39 +* scf_create_it - create Schur complement factorization 1.40 +* 1.41 +* SYNOPSIS 1.42 +* 1.43 +* #include "glpscf.h" 1.44 +* SCF *scf_create_it(int n_max); 1.45 +* 1.46 +* DESCRIPTION 1.47 +* 1.48 +* The routine scf_create_it creates the factorization of matrix C, 1.49 +* which initially has no rows and columns. 1.50 +* 1.51 +* The parameter n_max specifies the maximal order of matrix C to be 1.52 +* factorized, 1 <= n_max <= 32767. 1.53 +* 1.54 +* RETURNS 1.55 +* 1.56 +* The routine scf_create_it returns a pointer to the structure SCF, 1.57 +* which defines the factorization. */ 1.58 + 1.59 +SCF *scf_create_it(int n_max) 1.60 +{ SCF *scf; 1.61 +#if _GLPSCF_DEBUG 1.62 + xprintf("scf_create_it: warning: debug mode enabled\n"); 1.63 +#endif 1.64 + if (!(1 <= n_max && n_max <= 32767)) 1.65 + xfault("scf_create_it: n_max = %d; invalid parameter\n", 1.66 + n_max); 1.67 + scf = xmalloc(sizeof(SCF)); 1.68 + scf->n_max = n_max; 1.69 + scf->n = 0; 1.70 + scf->f = xcalloc(1 + n_max * n_max, sizeof(double)); 1.71 + scf->u = xcalloc(1 + n_max * (n_max + 1) / 2, sizeof(double)); 1.72 + scf->p = xcalloc(1 + n_max, sizeof(int)); 1.73 + scf->t_opt = SCF_TBG; 1.74 + scf->rank = 0; 1.75 +#if _GLPSCF_DEBUG 1.76 + scf->c = xcalloc(1 + n_max * n_max, sizeof(double)); 1.77 +#else 1.78 + scf->c = NULL; 1.79 +#endif 1.80 + scf->w = xcalloc(1 + n_max, sizeof(double)); 1.81 + return scf; 1.82 +} 1.83 + 1.84 +/*********************************************************************** 1.85 +* The routine f_loc determines location of matrix element F[i,j] in 1.86 +* the one-dimensional array f. */ 1.87 + 1.88 +static int f_loc(SCF *scf, int i, int j) 1.89 +{ int n_max = scf->n_max; 1.90 + int n = scf->n; 1.91 + xassert(1 <= i && i <= n); 1.92 + xassert(1 <= j && j <= n); 1.93 + return (i - 1) * n_max + j; 1.94 +} 1.95 + 1.96 +/*********************************************************************** 1.97 +* The routine u_loc determines location of matrix element U[i,j] in 1.98 +* the one-dimensional array u. */ 1.99 + 1.100 +static int u_loc(SCF *scf, int i, int j) 1.101 +{ int n_max = scf->n_max; 1.102 + int n = scf->n; 1.103 + xassert(1 <= i && i <= n); 1.104 + xassert(i <= j && j <= n); 1.105 + return (i - 1) * n_max + j - i * (i - 1) / 2; 1.106 +} 1.107 + 1.108 +/*********************************************************************** 1.109 +* The routine bg_transform applies Bartels-Golub version of gaussian 1.110 +* elimination to restore triangular structure of matrix U. 1.111 +* 1.112 +* On entry matrix U has the following structure: 1.113 +* 1.114 +* 1 k n 1.115 +* 1 * * * * * * * * * * 1.116 +* . * * * * * * * * * 1.117 +* . . * * * * * * * * 1.118 +* . . . * * * * * * * 1.119 +* k . . . . * * * * * * 1.120 +* . . . . . * * * * * 1.121 +* . . . . . . * * * * 1.122 +* . . . . . . . * * * 1.123 +* . . . . . . . . * * 1.124 +* n . . . . # # # # # # 1.125 +* 1.126 +* where '#' is a row spike to be eliminated. 1.127 +* 1.128 +* Elements of n-th row are passed separately in locations un[k], ..., 1.129 +* un[n]. On exit the content of the array un is destroyed. 1.130 +* 1.131 +* REFERENCES 1.132 +* 1.133 +* R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming 1.134 +* Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */ 1.135 + 1.136 +static void bg_transform(SCF *scf, int k, double un[]) 1.137 +{ int n = scf->n; 1.138 + double *f = scf->f; 1.139 + double *u = scf->u; 1.140 + int j, k1, kj, kk, n1, nj; 1.141 + double t; 1.142 + xassert(1 <= k && k <= n); 1.143 + /* main elimination loop */ 1.144 + for (k = k; k < n; k++) 1.145 + { /* determine location of U[k,k] */ 1.146 + kk = u_loc(scf, k, k); 1.147 + /* determine location of F[k,1] */ 1.148 + k1 = f_loc(scf, k, 1); 1.149 + /* determine location of F[n,1] */ 1.150 + n1 = f_loc(scf, n, 1); 1.151 + /* if |U[k,k]| < |U[n,k]|, interchange k-th and n-th rows to 1.152 + provide |U[k,k]| >= |U[n,k]| */ 1.153 + if (fabs(u[kk]) < fabs(un[k])) 1.154 + { /* interchange k-th and n-th rows of matrix U */ 1.155 + for (j = k, kj = kk; j <= n; j++, kj++) 1.156 + t = u[kj], u[kj] = un[j], un[j] = t; 1.157 + /* interchange k-th and n-th rows of matrix F to keep the 1.158 + main equality F * C = U * P */ 1.159 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) 1.160 + t = f[kj], f[kj] = f[nj], f[nj] = t; 1.161 + } 1.162 + /* now |U[k,k]| >= |U[n,k]| */ 1.163 + /* if U[k,k] is too small in the magnitude, replace U[k,k] and 1.164 + U[n,k] by exact zero */ 1.165 + if (fabs(u[kk]) < eps) u[kk] = un[k] = 0.0; 1.166 + /* if U[n,k] is already zero, elimination is not needed */ 1.167 + if (un[k] == 0.0) continue; 1.168 + /* compute gaussian multiplier t = U[n,k] / U[k,k] */ 1.169 + t = un[k] / u[kk]; 1.170 + /* apply gaussian elimination to nullify U[n,k] */ 1.171 + /* (n-th row of U) := (n-th row of U) - t * (k-th row of U) */ 1.172 + for (j = k+1, kj = kk+1; j <= n; j++, kj++) 1.173 + un[j] -= t * u[kj]; 1.174 + /* (n-th row of F) := (n-th row of F) - t * (k-th row of F) 1.175 + to keep the main equality F * C = U * P */ 1.176 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) 1.177 + f[nj] -= t * f[kj]; 1.178 + } 1.179 + /* if U[n,n] is too small in the magnitude, replace it by exact 1.180 + zero */ 1.181 + if (fabs(un[n]) < eps) un[n] = 0.0; 1.182 + /* store U[n,n] in a proper location */ 1.183 + u[u_loc(scf, n, n)] = un[n]; 1.184 + return; 1.185 +} 1.186 + 1.187 +/*********************************************************************** 1.188 +* The routine givens computes the parameters of Givens plane rotation 1.189 +* c = cos(teta) and s = sin(teta) such that: 1.190 +* 1.191 +* ( c -s ) ( a ) ( r ) 1.192 +* ( ) ( ) = ( ) , 1.193 +* ( s c ) ( b ) ( 0 ) 1.194 +* 1.195 +* where a and b are given scalars. 1.196 +* 1.197 +* REFERENCES 1.198 +* 1.199 +* G.H.Golub, C.F.Van Loan, "Matrix Computations", 2nd ed. */ 1.200 + 1.201 +static void givens(double a, double b, double *c, double *s) 1.202 +{ double t; 1.203 + if (b == 0.0) 1.204 + (*c) = 1.0, (*s) = 0.0; 1.205 + else if (fabs(a) <= fabs(b)) 1.206 + t = - a / b, (*s) = 1.0 / sqrt(1.0 + t * t), (*c) = (*s) * t; 1.207 + else 1.208 + t = - b / a, (*c) = 1.0 / sqrt(1.0 + t * t), (*s) = (*c) * t; 1.209 + return; 1.210 +} 1.211 + 1.212 +/*---------------------------------------------------------------------- 1.213 +* The routine gr_transform applies Givens plane rotations to restore 1.214 +* triangular structure of matrix U. 1.215 +* 1.216 +* On entry matrix U has the following structure: 1.217 +* 1.218 +* 1 k n 1.219 +* 1 * * * * * * * * * * 1.220 +* . * * * * * * * * * 1.221 +* . . * * * * * * * * 1.222 +* . . . * * * * * * * 1.223 +* k . . . . * * * * * * 1.224 +* . . . . . * * * * * 1.225 +* . . . . . . * * * * 1.226 +* . . . . . . . * * * 1.227 +* . . . . . . . . * * 1.228 +* n . . . . # # # # # # 1.229 +* 1.230 +* where '#' is a row spike to be eliminated. 1.231 +* 1.232 +* Elements of n-th row are passed separately in locations un[k], ..., 1.233 +* un[n]. On exit the content of the array un is destroyed. 1.234 +* 1.235 +* REFERENCES 1.236 +* 1.237 +* R.H.Bartels, G.H.Golub, "The Simplex Method of Linear Programming 1.238 +* Using LU-decomposition", Comm. ACM, 12, pp. 266-68, 1969. */ 1.239 + 1.240 +static void gr_transform(SCF *scf, int k, double un[]) 1.241 +{ int n = scf->n; 1.242 + double *f = scf->f; 1.243 + double *u = scf->u; 1.244 + int j, k1, kj, kk, n1, nj; 1.245 + double c, s; 1.246 + xassert(1 <= k && k <= n); 1.247 + /* main elimination loop */ 1.248 + for (k = k; k < n; k++) 1.249 + { /* determine location of U[k,k] */ 1.250 + kk = u_loc(scf, k, k); 1.251 + /* determine location of F[k,1] */ 1.252 + k1 = f_loc(scf, k, 1); 1.253 + /* determine location of F[n,1] */ 1.254 + n1 = f_loc(scf, n, 1); 1.255 + /* if both U[k,k] and U[n,k] are too small in the magnitude, 1.256 + replace them by exact zero */ 1.257 + if (fabs(u[kk]) < eps && fabs(un[k]) < eps) 1.258 + u[kk] = un[k] = 0.0; 1.259 + /* if U[n,k] is already zero, elimination is not needed */ 1.260 + if (un[k] == 0.0) continue; 1.261 + /* compute the parameters of Givens plane rotation */ 1.262 + givens(u[kk], un[k], &c, &s); 1.263 + /* apply Givens rotation to k-th and n-th rows of matrix U */ 1.264 + for (j = k, kj = kk; j <= n; j++, kj++) 1.265 + { double ukj = u[kj], unj = un[j]; 1.266 + u[kj] = c * ukj - s * unj; 1.267 + un[j] = s * ukj + c * unj; 1.268 + } 1.269 + /* apply Givens rotation to k-th and n-th rows of matrix F 1.270 + to keep the main equality F * C = U * P */ 1.271 + for (j = 1, kj = k1, nj = n1; j <= n; j++, kj++, nj++) 1.272 + { double fkj = f[kj], fnj = f[nj]; 1.273 + f[kj] = c * fkj - s * fnj; 1.274 + f[nj] = s * fkj + c * fnj; 1.275 + } 1.276 + } 1.277 + /* if U[n,n] is too small in the magnitude, replace it by exact 1.278 + zero */ 1.279 + if (fabs(un[n]) < eps) un[n] = 0.0; 1.280 + /* store U[n,n] in a proper location */ 1.281 + u[u_loc(scf, n, n)] = un[n]; 1.282 + return; 1.283 +} 1.284 + 1.285 +/*********************************************************************** 1.286 +* The routine transform restores triangular structure of matrix U. 1.287 +* It is a driver to the routines bg_transform and gr_transform (see 1.288 +* comments to these routines above). */ 1.289 + 1.290 +static void transform(SCF *scf, int k, double un[]) 1.291 +{ switch (scf->t_opt) 1.292 + { case SCF_TBG: 1.293 + bg_transform(scf, k, un); 1.294 + break; 1.295 + case SCF_TGR: 1.296 + gr_transform(scf, k, un); 1.297 + break; 1.298 + default: 1.299 + xassert(scf != scf); 1.300 + } 1.301 + return; 1.302 +} 1.303 + 1.304 +/*********************************************************************** 1.305 +* The routine estimate_rank estimates the rank of matrix C. 1.306 +* 1.307 +* Since all transformations applied to matrix F are non-singular, 1.308 +* and F is assumed to be well conditioned, from the main equaility 1.309 +* F * C = U * P it follows that rank(C) = rank(U), where rank(U) is 1.310 +* estimated as the number of non-zero diagonal elements of U. */ 1.311 + 1.312 +static int estimate_rank(SCF *scf) 1.313 +{ int n_max = scf->n_max; 1.314 + int n = scf->n; 1.315 + double *u = scf->u; 1.316 + int i, ii, inc, rank = 0; 1.317 + for (i = 1, ii = u_loc(scf, i, i), inc = n_max; i <= n; 1.318 + i++, ii += inc, inc--) 1.319 + if (u[ii] != 0.0) rank++; 1.320 + return rank; 1.321 +} 1.322 + 1.323 +#if _GLPSCF_DEBUG 1.324 +/*********************************************************************** 1.325 +* The routine check_error computes the maximal relative error between 1.326 +* left- and right-hand sides of the main equality F * C = U * P. (This 1.327 +* routine is intended only for debugging.) */ 1.328 + 1.329 +static void check_error(SCF *scf, const char *func) 1.330 +{ int n = scf->n; 1.331 + double *f = scf->f; 1.332 + double *u = scf->u; 1.333 + int *p = scf->p; 1.334 + double *c = scf->c; 1.335 + int i, j, k; 1.336 + double d, dmax = 0.0, s, t; 1.337 + xassert(c != NULL); 1.338 + for (i = 1; i <= n; i++) 1.339 + { for (j = 1; j <= n; j++) 1.340 + { /* compute element (i,j) of product F * C */ 1.341 + s = 0.0; 1.342 + for (k = 1; k <= n; k++) 1.343 + s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)]; 1.344 + /* compute element (i,j) of product U * P */ 1.345 + k = p[j]; 1.346 + t = (i <= k ? u[u_loc(scf, i, k)] : 0.0); 1.347 + /* compute the maximal relative error */ 1.348 + d = fabs(s - t) / (1.0 + fabs(t)); 1.349 + if (dmax < d) dmax = d; 1.350 + } 1.351 + } 1.352 + if (dmax > 1e-8) 1.353 + xprintf("%s: dmax = %g; relative error too large\n", func, 1.354 + dmax); 1.355 + return; 1.356 +} 1.357 +#endif 1.358 + 1.359 +/*********************************************************************** 1.360 +* NAME 1.361 +* 1.362 +* scf_update_exp - update factorization on expanding C 1.363 +* 1.364 +* SYNOPSIS 1.365 +* 1.366 +* #include "glpscf.h" 1.367 +* int scf_update_exp(SCF *scf, const double x[], const double y[], 1.368 +* double z); 1.369 +* 1.370 +* DESCRIPTION 1.371 +* 1.372 +* The routine scf_update_exp updates the factorization of matrix C on 1.373 +* expanding it by adding a new row and column as follows: 1.374 +* 1.375 +* ( C x ) 1.376 +* new C = ( ) 1.377 +* ( y' z ) 1.378 +* 1.379 +* where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is 1.380 +* a new diagonal element. 1.381 +* 1.382 +* If on entry the factorization is empty, the parameters x and y can 1.383 +* be specified as NULL. 1.384 +* 1.385 +* RETURNS 1.386 +* 1.387 +* 0 The factorization has been successfully updated. 1.388 +* 1.389 +* SCF_ESING 1.390 +* The factorization has been successfully updated, however, new 1.391 +* matrix C is singular within working precision. Note that the new 1.392 +* factorization remains valid. 1.393 +* 1.394 +* SCF_ELIMIT 1.395 +* There is not enough room to expand the factorization, because 1.396 +* n = n_max. The factorization remains unchanged. 1.397 +* 1.398 +* ALGORITHM 1.399 +* 1.400 +* We can see that: 1.401 +* 1.402 +* ( F 0 ) ( C x ) ( FC Fx ) ( UP Fx ) 1.403 +* ( ) ( ) = ( ) = ( ) = 1.404 +* ( 0 1 ) ( y' z ) ( y' z ) ( y' z ) 1.405 +* 1.406 +* ( U Fx ) ( P 0 ) 1.407 +* = ( ) ( ), 1.408 +* ( y'P' z ) ( 0 1 ) 1.409 +* 1.410 +* therefore to keep the main equality F * C = U * P we can take: 1.411 +* 1.412 +* ( F 0 ) ( U Fx ) ( P 0 ) 1.413 +* new F = ( ), new U = ( ), new P = ( ), 1.414 +* ( 0 1 ) ( y'P' z ) ( 0 1 ) 1.415 +* 1.416 +* and eliminate the row spike y'P' in the last row of new U to restore 1.417 +* its upper triangular structure. */ 1.418 + 1.419 +int scf_update_exp(SCF *scf, const double x[], const double y[], 1.420 + double z) 1.421 +{ int n_max = scf->n_max; 1.422 + int n = scf->n; 1.423 + double *f = scf->f; 1.424 + double *u = scf->u; 1.425 + int *p = scf->p; 1.426 +#if _GLPSCF_DEBUG 1.427 + double *c = scf->c; 1.428 +#endif 1.429 + double *un = scf->w; 1.430 + int i, ij, in, j, k, nj, ret = 0; 1.431 + double t; 1.432 + /* check if the factorization can be expanded */ 1.433 + if (n == n_max) 1.434 + { /* there is not enough room */ 1.435 + ret = SCF_ELIMIT; 1.436 + goto done; 1.437 + } 1.438 + /* increase the order of the factorization */ 1.439 + scf->n = ++n; 1.440 + /* fill new zero column of matrix F */ 1.441 + for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) 1.442 + f[in] = 0.0; 1.443 + /* fill new zero row of matrix F */ 1.444 + for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) 1.445 + f[nj] = 0.0; 1.446 + /* fill new unity diagonal element of matrix F */ 1.447 + f[f_loc(scf, n, n)] = 1.0; 1.448 + /* compute new column of matrix U, which is (old F) * x */ 1.449 + for (i = 1; i < n; i++) 1.450 + { /* u[i,n] := (i-th row of old F) * x */ 1.451 + t = 0.0; 1.452 + for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++) 1.453 + t += f[ij] * x[j]; 1.454 + u[u_loc(scf, i, n)] = t; 1.455 + } 1.456 + /* compute new (spiked) row of matrix U, which is (old P) * y */ 1.457 + for (j = 1; j < n; j++) un[j] = y[p[j]]; 1.458 + /* store new diagonal element of matrix U, which is z */ 1.459 + un[n] = z; 1.460 + /* expand matrix P */ 1.461 + p[n] = n; 1.462 +#if _GLPSCF_DEBUG 1.463 + /* expand matrix C */ 1.464 + /* fill its new column, which is x */ 1.465 + for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) 1.466 + c[in] = x[i]; 1.467 + /* fill its new row, which is y */ 1.468 + for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) 1.469 + c[nj] = y[j]; 1.470 + /* fill its new diagonal element, which is z */ 1.471 + c[f_loc(scf, n, n)] = z; 1.472 +#endif 1.473 + /* restore upper triangular structure of matrix U */ 1.474 + for (k = 1; k < n; k++) 1.475 + if (un[k] != 0.0) break; 1.476 + transform(scf, k, un); 1.477 + /* estimate the rank of matrices C and U */ 1.478 + scf->rank = estimate_rank(scf); 1.479 + if (scf->rank != n) ret = SCF_ESING; 1.480 +#if _GLPSCF_DEBUG 1.481 + /* check that the factorization is accurate enough */ 1.482 + check_error(scf, "scf_update_exp"); 1.483 +#endif 1.484 +done: return ret; 1.485 +} 1.486 + 1.487 +/*********************************************************************** 1.488 +* The routine solve solves the system C * x = b. 1.489 +* 1.490 +* From the main equation F * C = U * P it follows that: 1.491 +* 1.492 +* C * x = b => F * C * x = F * b => U * P * x = F * b => 1.493 +* 1.494 +* P * x = inv(U) * F * b => x = P' * inv(U) * F * b. 1.495 +* 1.496 +* On entry the array x contains right-hand side vector b. On exit this 1.497 +* array contains solution vector x. */ 1.498 + 1.499 +static void solve(SCF *scf, double x[]) 1.500 +{ int n = scf->n; 1.501 + double *f = scf->f; 1.502 + double *u = scf->u; 1.503 + int *p = scf->p; 1.504 + double *y = scf->w; 1.505 + int i, j, ij; 1.506 + double t; 1.507 + /* y := F * b */ 1.508 + for (i = 1; i <= n; i++) 1.509 + { /* y[i] = (i-th row of F) * b */ 1.510 + t = 0.0; 1.511 + for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) 1.512 + t += f[ij] * x[j]; 1.513 + y[i] = t; 1.514 + } 1.515 + /* y := inv(U) * y */ 1.516 + for (i = n; i >= 1; i--) 1.517 + { t = y[i]; 1.518 + for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--) 1.519 + t -= u[ij] * y[j]; 1.520 + y[i] = t / u[ij]; 1.521 + } 1.522 + /* x := P' * y */ 1.523 + for (i = 1; i <= n; i++) x[p[i]] = y[i]; 1.524 + return; 1.525 +} 1.526 + 1.527 +/*********************************************************************** 1.528 +* The routine tsolve solves the transposed system C' * x = b. 1.529 +* 1.530 +* From the main equation F * C = U * P it follows that: 1.531 +* 1.532 +* C' * F' = P' * U', 1.533 +* 1.534 +* therefore: 1.535 +* 1.536 +* C' * x = b => C' * F' * inv(F') * x = b => 1.537 +* 1.538 +* P' * U' * inv(F') * x = b => U' * inv(F') * x = P * b => 1.539 +* 1.540 +* inv(F') * x = inv(U') * P * b => x = F' * inv(U') * P * b. 1.541 +* 1.542 +* On entry the array x contains right-hand side vector b. On exit this 1.543 +* array contains solution vector x. */ 1.544 + 1.545 +static void tsolve(SCF *scf, double x[]) 1.546 +{ int n = scf->n; 1.547 + double *f = scf->f; 1.548 + double *u = scf->u; 1.549 + int *p = scf->p; 1.550 + double *y = scf->w; 1.551 + int i, j, ij; 1.552 + double t; 1.553 + /* y := P * b */ 1.554 + for (i = 1; i <= n; i++) y[i] = x[p[i]]; 1.555 + /* y := inv(U') * y */ 1.556 + for (i = 1; i <= n; i++) 1.557 + { /* compute y[i] */ 1.558 + ij = u_loc(scf, i, i); 1.559 + t = (y[i] /= u[ij]); 1.560 + /* substitute y[i] in other equations */ 1.561 + for (j = i+1, ij++; j <= n; j++, ij++) 1.562 + y[j] -= u[ij] * t; 1.563 + } 1.564 + /* x := F' * y (computed as linear combination of rows of F) */ 1.565 + for (j = 1; j <= n; j++) x[j] = 0.0; 1.566 + for (i = 1; i <= n; i++) 1.567 + { t = y[i]; /* coefficient of linear combination */ 1.568 + for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) 1.569 + x[j] += f[ij] * t; 1.570 + } 1.571 + return; 1.572 +} 1.573 + 1.574 +/*********************************************************************** 1.575 +* NAME 1.576 +* 1.577 +* scf_solve_it - solve either system C * x = b or C' * x = b 1.578 +* 1.579 +* SYNOPSIS 1.580 +* 1.581 +* #include "glpscf.h" 1.582 +* void scf_solve_it(SCF *scf, int tr, double x[]); 1.583 +* 1.584 +* DESCRIPTION 1.585 +* 1.586 +* The routine scf_solve_it solves either the system C * x = b (if tr 1.587 +* is zero) or the system C' * x = b, where C' is a matrix transposed 1.588 +* to C (if tr is non-zero). C is assumed to be non-singular. 1.589 +* 1.590 +* On entry the array x should contain the right-hand side vector b in 1.591 +* locations x[1], ..., x[n], where n is the order of matrix C. On exit 1.592 +* the array x contains the solution vector x in the same locations. */ 1.593 + 1.594 +void scf_solve_it(SCF *scf, int tr, double x[]) 1.595 +{ if (scf->rank < scf->n) 1.596 + xfault("scf_solve_it: singular matrix\n"); 1.597 + if (!tr) 1.598 + solve(scf, x); 1.599 + else 1.600 + tsolve(scf, x); 1.601 + return; 1.602 +} 1.603 + 1.604 +void scf_reset_it(SCF *scf) 1.605 +{ /* reset factorization for empty matrix C */ 1.606 + scf->n = scf->rank = 0; 1.607 + return; 1.608 +} 1.609 + 1.610 +/*********************************************************************** 1.611 +* NAME 1.612 +* 1.613 +* scf_delete_it - delete Schur complement factorization 1.614 +* 1.615 +* SYNOPSIS 1.616 +* 1.617 +* #include "glpscf.h" 1.618 +* void scf_delete_it(SCF *scf); 1.619 +* 1.620 +* DESCRIPTION 1.621 +* 1.622 +* The routine scf_delete_it deletes the specified factorization and 1.623 +* frees all the memory allocated to this object. */ 1.624 + 1.625 +void scf_delete_it(SCF *scf) 1.626 +{ xfree(scf->f); 1.627 + xfree(scf->u); 1.628 + xfree(scf->p); 1.629 +#if _GLPSCF_DEBUG 1.630 + xfree(scf->c); 1.631 +#endif 1.632 + xfree(scf->w); 1.633 + xfree(scf); 1.634 + return; 1.635 +} 1.636 + 1.637 +/* eof */