📄 glpscf.c
字号:
#if _GLPSCF_DEBUG/************************************************************************ The routine check_error computes the maximal relative error between* left- and right-hand sides of the main equality F * C = U * P. (This* routine is intended only for debugging.) */static void check_error(SCF *scf, const char *func){ int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *c = scf->c; int i, j, k; double d, dmax = 0.0, s, t; xassert(c != NULL); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { /* compute element (i,j) of product F * C */ s = 0.0; for (k = 1; k <= n; k++) s += f[f_loc(scf, i, k)] * c[f_loc(scf, k, j)]; /* compute element (i,j) of product U * P */ k = p[j]; t = (i <= k ? u[u_loc(scf, i, k)] : 0.0); /* compute the maximal relative error */ d = fabs(s - t) / (1.0 + fabs(t)); if (dmax < d) dmax = d; } } if (dmax > 1e-8) xprintf("%s: dmax = %g; relative error too large\n", func, dmax); return;}#endif/************************************************************************ NAME** scf_update_exp - update factorization on expanding C** SYNOPSIS** #include "glpscf.h"* int scf_update_exp(SCF *scf, const double x[], const double y[],* double z);** DESCRIPTION** The routine scf_update_exp updates the factorization of matrix C on* expanding it by adding a new row and column as follows:** ( C x )* new C = ( )* ( y' z )** where x[1,...,n] is a new column, y[1,...,n] is a new row, and z is* a new diagonal element.** If on entry the factorization is empty, the parameters x and y can* be specified as NULL.** RETURNS** 0 The factorization has been successfully updated.** SCF_ESING* The factorization has been successfully updated, however, new* matrix C is singular within working precision. Note that the new* factorization remains valid.** SCF_ELIMIT* There is not enough room to expand the factorization, because* n = n_max. The factorization remains unchanged.** ALGORITHM** We can see that:** ( F 0 ) ( C x ) ( FC Fx ) ( UP Fx )* ( ) ( ) = ( ) = ( ) =* ( 0 1 ) ( y' z ) ( y' z ) ( y' z )** ( U Fx ) ( P 0 )* = ( ) ( ),* ( y'P' z ) ( 0 1 )** therefore to keep the main equality F * C = U * P we can take:** ( F 0 ) ( U Fx ) ( P 0 )* new F = ( ), new U = ( ), new P = ( ),* ( 0 1 ) ( y'P' z ) ( 0 1 )** and eliminate the row spike y'P' in the last row of new U to restore* its upper triangular structure. */int scf_update_exp(SCF *scf, const double x[], const double y[], double z){ int n_max = scf->n_max; int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p;#if _GLPSCF_DEBUG double *c = scf->c;#endif double *un = scf->w; int i, ij, in, j, k, nj, ret = 0; double t; /* check if the factorization can be expanded */ if (n == n_max) { /* there is not enough room */ ret = SCF_ELIMIT; goto done; } /* increase the order of the factorization */ scf->n = ++n; /* fill new zero column of matrix F */ for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) f[in] = 0.0; /* fill new zero row of matrix F */ for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) f[nj] = 0.0; /* fill new unity diagonal element of matrix F */ f[f_loc(scf, n, n)] = 1.0; /* compute new column of matrix U, which is (old F) * x */ for (i = 1; i < n; i++) { /* u[i,n] := (i-th row of old F) * x */ t = 0.0; for (j = 1, ij = f_loc(scf, i, 1); j < n; j++, ij++) t += f[ij] * x[j]; u[u_loc(scf, i, n)] = t; } /* compute new (spiked) row of matrix U, which is (old P) * y */ for (j = 1; j < n; j++) un[j] = y[p[j]]; /* store new diagonal element of matrix U, which is z */ un[n] = z; /* expand matrix P */ p[n] = n;#if _GLPSCF_DEBUG /* expand matrix C */ /* fill its new column, which is x */ for (i = 1, in = f_loc(scf, i, n); i < n; i++, in += n_max) c[in] = x[i]; /* fill its new row, which is y */ for (j = 1, nj = f_loc(scf, n, j); j < n; j++, nj++) c[nj] = y[j]; /* fill its new diagonal element, which is z */ c[f_loc(scf, n, n)] = z;#endif /* restore upper triangular structure of matrix U */ for (k = 1; k < n; k++) if (un[k] != 0.0) break; transform(scf, k, un); /* estimate the rank of matrices C and U */ scf->rank = estimate_rank(scf); if (scf->rank != n) ret = SCF_ESING;#if _GLPSCF_DEBUG /* check that the factorization is accurate enough */ check_error(scf, "scf_update_exp");#endifdone: return ret;}/************************************************************************ The routine solve solves the system C * x = b.** From the main equation F * C = U * P it follows that:** C * x = b => F * C * x = F * b => U * P * x = F * b =>** P * x = inv(U) * F * b => x = P' * inv(U) * F * b.** On entry the array x contains right-hand side vector b. On exit this* array contains solution vector x. */static void solve(SCF *scf, double x[]){ int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *y = scf->w; int i, j, ij; double t; /* y := F * b */ for (i = 1; i <= n; i++) { /* y[i] = (i-th row of F) * b */ t = 0.0; for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) t += f[ij] * x[j]; y[i] = t; } /* y := inv(U) * y */ for (i = n; i >= 1; i--) { t = y[i]; for (j = n, ij = u_loc(scf, i, n); j > i; j--, ij--) t -= u[ij] * y[j]; y[i] = t / u[ij]; } /* x := P' * y */ for (i = 1; i <= n; i++) x[p[i]] = y[i]; return;}/************************************************************************ The routine tsolve solves the transposed system C' * x = b.** From the main equation F * C = U * P it follows that:** C' * F' = P' * U',** therefore:** C' * x = b => C' * F' * inv(F') * x = b =>** P' * U' * inv(F') * x = b => U' * inv(F') * x = P * b =>** inv(F') * x = inv(U') * P * b => x = F' * inv(U') * P * b.** On entry the array x contains right-hand side vector b. On exit this* array contains solution vector x. */static void tsolve(SCF *scf, double x[]){ int n = scf->n; double *f = scf->f; double *u = scf->u; int *p = scf->p; double *y = scf->w; int i, j, ij; double t; /* y := P * b */ for (i = 1; i <= n; i++) y[i] = x[p[i]]; /* y := inv(U') * y */ for (i = 1; i <= n; i++) { /* compute y[i] */ ij = u_loc(scf, i, i); t = (y[i] /= u[ij]); /* substitute y[i] in other equations */ for (j = i+1, ij++; j <= n; j++, ij++) y[j] -= u[ij] * t; } /* x := F' * y (computed as linear combination of rows of F) */ for (j = 1; j <= n; j++) x[j] = 0.0; for (i = 1; i <= n; i++) { t = y[i]; /* coefficient of linear combination */ for (j = 1, ij = f_loc(scf, i, 1); j <= n; j++, ij++) x[j] += f[ij] * t; } return;}/************************************************************************ NAME** scf_solve_it - solve either system C * x = b or C' * x = b** SYNOPSIS** #include "glpscf.h"* void scf_solve_it(SCF *scf, int tr, double x[]);** DESCRIPTION** The routine scf_solve_it solves either the system C * x = b (if tr* is zero) or the system C' * x = b, where C' is a matrix transposed* to C (if tr is non-zero). C is assumed to be non-singular.** On entry the array x should contain the right-hand side vector b in* locations x[1], ..., x[n], where n is the order of matrix C. On exit* the array x contains the solution vector x in the same locations. */void scf_solve_it(SCF *scf, int tr, double x[]){ if (scf->rank < scf->n) xfault("scf_solve_it: singular matrix\n"); if (!tr) solve(scf, x); else tsolve(scf, x); return;}void scf_reset_it(SCF *scf){ /* reset factorization for empty matrix C */ scf->n = scf->rank = 0; return;}/************************************************************************ NAME** scf_delete_it - delete Schur complement factorization** SYNOPSIS** #include "glpscf.h"* void scf_delete_it(SCF *scf);** DESCRIPTION** The routine scf_delete_it deletes the specified factorization and* frees all the memory allocated to this object. */void scf_delete_it(SCF *scf){ xfree(scf->f); xfree(scf->u); xfree(scf->p);#if _GLPSCF_DEBUG xfree(scf->c);#endif xfree(scf->w); xfree(scf); return;}/* eof */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -