Cloned SEACAS for EXODUS library with extra build files for internal package management.
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.
 
 
 
 
 
 

219 lines
8.2 KiB

/*
* Copyright(C) 1999-2020, 2023 National Technology & Engineering Solutions
* of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
* NTESS, the U.S. Government retains certain rights in this software.
*
* See packages/seacas/LICENSE for details
*/
#include "defs.h" // for TRUE, FALSE, max, min
#include "smalloc.h" // for sfree, smalloc
#include "structs.h"
#include <stdio.h> // for printf, NULL
/* Perform Rayleigh Quotient Iteration */
void rqi(struct vtx_data **A, /* matrix/graph being analyzed */
double **yvecs, /* eigenvectors to be refined */
int index, /* index of vector in yvecs to be refined */
int n, /* number of rows/columns in matrix */
double *r1, double *r2, double *v, double *w, double *x, double *y,
double *work, /* work space for symmlq */
double tol, /* error tolerance in eigenpair */
double initshift, /* initial shift */
double *evalest, /* returned eigenvalue */
double *vwsqrt, /* square roots of vertex weights */
struct orthlink *orthlist, /* lower evecs to orthogonalize against */
int cube_or_mesh, /* 0 => hypercube, d => d-dimensional mesh */
int nsets, /* number of sets to divide into */
int *assignment, /* set number of each vtx (length n+1) */
int *active, /* space for nvtxs integers */
int mediantype, /* which partitioning strategy to use */
double *goal, /* desired set sizes */
int vwgt_max, /* largest vertex weight */
int ndims /* dimensionality of partition */
)
{
extern int DEBUG_EVECS; /* debug flag for eigen computation */
extern int DEBUG_TRACE; /* trace main execution path */
extern int WARNING_EVECS; /* warning flag for eigen computation */
extern int RQI_CONVERGENCE_MODE; /* type of convergence monitoring to do */
int rqisteps; /* # rqi rqisteps */
double res; /* convergence quant for rqi */
double last_res; /* res on previous rqi step */
double macheps; /* machine precision calculated by symmlq */
double normxlim; /* a stopping criteria for symmlq */
double normx; /* norm of the solution vector */
int symmlqitns; /* # symmlq itns */
int inv_it_steps; /* initial steps of inverse iteration */
long itnmin; /* symmlq input */
double shift, rtol; /* symmlq input */
long precon, goodb, nout; /* symmlq input */
long checka, intlim; /* symmlq input */
double anorm, acond; /* symmlq output */
double rnorm, ynorm; /* symmlq output */
long istop, itn; /* symmlq output */
long long_n; /* copy of n for passing to symmlq */
int warning; /* warning on possible misconvergence */
double factor; /* ratio between previous res and new tol */
double minfactor; /* minimum acceptable value of factor */
int converged; /* has process converged yet? */
double *u; /* name of vector being refined */
int *old_assignment = NULL; /* previous assignment vector */
int *assgn_pntr; /* pntr to assignment vector */
int *old_assgn_pntr; /* pntr to previous assignment vector */
int assigndiff = 0; /* discrepancies between old and new assignment */
int assigntol = 0; /* tolerance on convergence of assignment vector */
int first; /* is this the first RQI step? */
int i; /* loop index */
if (DEBUG_TRACE > 0) {
printf("<Entering rqi>\n");
}
/* Initialize RQI loop */
u = yvecs[index];
splarax(y, A, n, u, vwsqrt, r1);
shift = dot(u, 1, n, y);
scadd(y, 1, n, -shift, u);
res = ch_norm(y, 1, n); /* eigen-residual */
rqisteps = 0; /* a counter */
symmlqitns = 0; /* a counter */
/* Set invariant symmlq parameters */
precon = FALSE; /* FALSE until we figure out a good way */
goodb = TRUE; /* should be TRUE for this application */
nout = 0; /* set to 0 for no Symmlq output; 6 for lots */
checka = FALSE; /* if don't know by now, too bad */
intlim = n; /* set to enforce a maximum number of Symmlq itns */
itnmin = 0; /* set to enforce a minimum number of Symmlq itns */
long_n = n; /* type change for alint */
if (DEBUG_EVECS > 0) {
printf("Using RQI/Symmlq refinement on graph with %d vertices.\n", n);
}
if (DEBUG_EVECS > 1) {
printf(" step lambda est. Ares Symmlq its. istop factor delta\n");
printf(" 0");
doubleout(shift, 1);
doubleout(res, 1);
printf("\n");
}
if (RQI_CONVERGENCE_MODE == 1) {
assigntol = tol * n;
old_assignment = smalloc((n + 1) * sizeof(int));
}
/* Perform RQI */
inv_it_steps = 2;
warning = FALSE;
factor = 10;
minfactor = factor / 2;
first = TRUE;
if (res < tol) {
converged = TRUE;
}
else {
converged = FALSE;
}
while (!converged) {
if (res / tol < 1.2) {
factor = max(factor / 2, minfactor);
}
rtol = res / factor;
/* exit Symmlq if iterate is this large */
normxlim = 1.0 / rtol;
if (rqisteps < inv_it_steps) {
shift = initshift;
}
symmlq(&long_n, &u[1], &r1[1], &r2[1], &v[1], &w[1], &x[1], &y[1], work, &checka, &goodb,
&precon, &shift, &nout, &intlim, &rtol, &istop, &itn, &anorm, &acond, &rnorm, &ynorm,
(double *)A, vwsqrt, (double *)orthlist, &macheps, &normxlim, &itnmin);
symmlqitns += itn;
normx = ch_norm(x, 1, n);
vecscale(u, 1, n, 1.0 / normx, x);
splarax(y, A, n, u, vwsqrt, r1);
shift = dot(u, 1, n, y);
scadd(y, 1, n, -shift, u);
last_res = res;
res = ch_norm(y, 1, n);
if (res > last_res) {
warning = TRUE;
}
rqisteps++;
if (res < tol) {
converged = TRUE;
}
if (RQI_CONVERGENCE_MODE == 1 && !converged && ndims == 1) {
if (first) {
assign(A, yvecs, n, 1, cube_or_mesh, nsets, vwsqrt, assignment, active, mediantype, goal,
vwgt_max);
x2y(yvecs, ndims, n, vwsqrt);
first = FALSE;
assigndiff = n; /* dummy value for debug chart */
}
else {
/* copy assignment to old_assignment */
assgn_pntr = assignment;
old_assgn_pntr = old_assignment;
for (i = n + 1; i; i--) {
*old_assgn_pntr++ = *assgn_pntr++;
}
assign(A, yvecs, n, ndims, cube_or_mesh, nsets, vwsqrt, assignment, active, mediantype,
goal, vwgt_max);
x2y(yvecs, ndims, n, vwsqrt);
/* count differences in assignment */
assigndiff = 0;
assgn_pntr = assignment;
old_assgn_pntr = old_assignment;
for (i = n + 1; i; i--) {
if (*old_assgn_pntr++ != *assgn_pntr++) {
assigndiff++;
}
}
assigndiff = min(assigndiff, n - assigndiff);
if (assigndiff <= assigntol) {
converged = TRUE;
}
}
}
if (DEBUG_EVECS > 1) {
printf(" %2d", rqisteps);
doubleout(shift, 1);
doubleout(res, 1);
printf(" %3ld", itn);
printf(" %ld", istop);
printf(" %g", factor);
if (RQI_CONVERGENCE_MODE == 1) {
printf(" %d\n", assigndiff);
}
else {
printf("\n");
}
}
}
*evalest = shift;
if (WARNING_EVECS > 0 && warning) {
strout("WARNING: Residual convergence not monotonic; RQI may have misconverged.\n");
}
if (DEBUG_EVECS > 0) {
printf("Eval ");
doubleout(*evalest, 1);
printf(" RQI steps %d, Symmlq iterations %d.\n\n", rqisteps, symmlqitns);
}
if (RQI_CONVERGENCE_MODE == 1) {
sfree(old_assignment);
}
}