/*  -- translated by f2c (version 20240504).
   You must link the resulting object file with libf2c:
	on Microsoft Windows system, link with libf2c.lib;
	on Linux or Unix systems, link with .../path/to/libf2c.a -lm
	or, if you install libf2c.a in a standard place, with -lf2c -lm
	-- in that order, at the end of the command line, as in
		cc *.o -lf2c -lm
	Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,

		http://www.netlib.org/f2c/libf2c.zip
*/

#include "f2c.h"

/* Table of constant values */

static doublereal c_b3 = .66666666666666663;
static integer c__1 = 1;
static integer c__0 = 0;
static integer c__4 = 4;
static logical c_true = TRUE_;
static integer c__2 = 2;

/* \BeginDoc

   \Name: dnaup2

   \Description:
    Intermediate level interface called by dnaupd .

   \Usage:
    call dnaup2
       ( IDO, BMAT, N, WHICH, NEV, NP, TOL, RESID, MODE, IUPD,
         ISHIFT, MXITER, V, LDV, H, LDH, RITZR, RITZI, BOUNDS,
         Q, LDQ, WORKL, IPNTR, WORKD, INFO )

   \Arguments

    IDO, BMAT, N, WHICH, NEV, TOL, RESID: same as defined in dnaupd .
    MODE, ISHIFT, MXITER: see the definition of IPARAM in dnaupd .

    NP      Integer.  (INPUT/OUTPUT)
            Contains the number of implicit shifts to apply during
            each Arnoldi iteration.
            If ISHIFT=1, NP is adjusted dynamically at each iteration
            to accelerate convergence and prevent stagnation.
            This is also roughly equal to the number of matrix-vector
            products (involving the operator OP) per Arnoldi iteration.
            The logic for adjusting is contained within the current
            subroutine.
            If ISHIFT=0, NP is the number of shifts the user needs
            to provide via reverse communication. 0 < NP < NCV-NEV.
            NP may be less than NCV-NEV for two reasons. The first, is
            to keep complex conjugate pairs of "wanted" Ritz values
            together. The second, is that a leading block of the current
            upper Hessenberg matrix has split off and contains "unwanted"
            Ritz values.
            Upon termination of the IRA iteration, NP contains the number
            of "converged" wanted Ritz values.

    IUPD    Integer.  (INPUT)
            IUPD .EQ. 0: use explicit restart instead implicit update.
            IUPD .NE. 0: use implicit update.

    V       Double precision  N by (NEV+NP) array.  (INPUT/OUTPUT)
            The Arnoldi basis vectors are returned in the first NEV
            columns of V.

    LDV     Integer.  (INPUT)
            Leading dimension of V exactly as declared in the calling
            program.

    H       Double precision  (NEV+NP) by (NEV+NP) array.  (OUTPUT)
            H is used to store the generated upper Hessenberg matrix

    LDH     Integer.  (INPUT)
            Leading dimension of H exactly as declared in the calling
            program.

    RITZR,  Double precision  arrays of length NEV+NP.  (OUTPUT)
    RITZI   RITZR(1:NEV) (resp. RITZI(1:NEV)) contains the real (resp.
            imaginary) part of the computed Ritz values of OP.

    BOUNDS  Double precision  array of length NEV+NP.  (OUTPUT)
            BOUNDS(1:NEV) contain the error bounds corresponding to
            the computed Ritz values.

    Q       Double precision  (NEV+NP) by (NEV+NP) array.  (WORKSPACE)
            Private (replicated) work array used to accumulate the
            rotation in the shift application step.

    LDQ     Integer.  (INPUT)
            Leading dimension of Q exactly as declared in the calling
            program.

    WORKL   Double precision  work array of length at least
            (NEV+NP)**2 + 3*(NEV+NP).  (INPUT/WORKSPACE)
            Private (replicated) array on each PE or array allocated on
            the front end.  It is used in shifts calculation, shifts
            application and convergence checking.

            On exit, the last 3*(NEV+NP) locations of WORKL contain
            the Ritz values (real,imaginary) and associated Ritz
            estimates of the current Hessenberg matrix.  They are
            listed in the same order as returned from dneigh .

            If ISHIFT .EQ. O and IDO .EQ. 3, the first 2*NP locations
            of WORKL are used in reverse communication to hold the user
            supplied shifts.

    IPNTR   Integer array of length 3.  (OUTPUT)
            Pointer to mark the starting locations in the WORKD for
            vectors used by the Arnoldi iteration.
            -------------------------------------------------------------
            IPNTR(1): pointer to the current operand vector X.
            IPNTR(2): pointer to the current result vector Y.
            IPNTR(3): pointer to the vector B * X when used in the
                      shift-and-invert mode.  X is the current operand.
            -------------------------------------------------------------

    WORKD   Double precision  work array of length 3*N.  (WORKSPACE)
            Distributed array to be used in the basic Arnoldi iteration
            for reverse communication.  The user should not use WORKD
            as temporary workspace during the iteration !!!!!!!!!!
            See Data Distribution Note in DNAUPD.

    INFO    Integer.  (INPUT/OUTPUT)
            If INFO .EQ. 0, a randomly initial residual vector is used.
            If INFO .NE. 0, RESID contains the initial residual vector,
                            possibly from a previous run.
            Error flag on output.
            =     0: Normal return.
            =     1: Maximum number of iterations taken.
                     All possible eigenvalues of OP has been found.
                     NP returns the number of converged Ritz values.
            =     2: No shifts could be applied.
            =    -8: Error return from LAPACK eigenvalue calculation;
                     This should never happen.
            =    -9: Starting vector is zero.
            = -9999: Could not build an Arnoldi factorization.
                     Size that was built in returned in NP.

   \EndDoc

   -----------------------------------------------------------------------

   \BeginLib

   \Local variables:
       xxxxxx  real

   \References:
    1. D.C. Sorensen, "Implicit Application of Polynomial Filters in
       a k-Step Arnoldi Method", SIAM J. Matr. Anal. Apps., 13 (1992),
       pp 357-385.
    2. R.B. Lehoucq, "Analysis and Implementation of an Implicitly
       Restarted Arnoldi Iteration", Rice University Technical Report
       TR95-13, Department of Computational and Applied Mathematics.

   \Routines called:
       dgetv0   ARPACK initial vector generation routine.
       dnaitr   ARPACK Arnoldi factorization routine.
       dnapps   ARPACK application of implicit shifts routine.
       dnconv   ARPACK convergence of Ritz values routine.
       dneigh   ARPACK compute Ritz values and error bounds routine.
       dngets   ARPACK reorder Ritz values and error bounds routine.
       dsortc   ARPACK sorting routine.
       ivout   ARPACK utility routine that prints integers.
       arscnd  ARPACK utility routine for timing.
       dmout    ARPACK utility routine that prints matrices
       dvout    ARPACK utility routine that prints vectors.
       dlamch   LAPACK routine that determines machine constants.
       dlapy2   LAPACK routine to compute sqrt(x**2+y**2) carefully.
       dcopy    Level 1 BLAS that copies one vector to another .
       ddot     Level 1 BLAS that computes the scalar product of two vectors.
       dnrm2    Level 1 BLAS that computes the norm of a vector.
       dswap    Level 1 BLAS that swaps two vectors.

   \Author
       Danny Sorensen               Phuong Vu
       Richard Lehoucq              CRPC / Rice University
       Dept. of Computational &     Houston, Texas
       Applied Mathematics
       Rice University
       Houston, Texas

   \SCCS Information: @(#)
   FILE: naup2.F   SID: 2.8   DATE OF SID: 10/17/00   RELEASE: 2

   \Remarks
       1. None

   \EndLib

   -----------------------------------------------------------------------

   Subroutine */ int igraphdnaup2_(integer *ido, char *bmat, integer *n, char *
	which, integer *nev, integer *np, doublereal *tol, doublereal *resid,
	integer *mode, integer *iupd, integer *ishift, integer *mxiter,
	doublereal *v, integer *ldv, doublereal *h__, integer *ldh,
	doublereal *ritzr, doublereal *ritzi, doublereal *bounds, doublereal *
	q, integer *ldq, doublereal *workl, integer *ipntr, doublereal *workd,
	 integer *info)
{
    /* System generated locals */
    integer h_dim1, h_offset, q_dim1, q_offset, v_dim1, v_offset, i__1, i__2;
    doublereal d__1, d__2;

    /* Builtin functions */
    double pow_dd(doublereal *, doublereal *);
    integer s_cmp(char *, char *, ftnlen, ftnlen);
    /* Subroutine */ int s_copy(char *, char *, ftnlen, ftnlen);
    double sqrt(doublereal);

    /* Local variables */
    integer j;
    real t0, t1, t2, t3;
    integer kp[4];
    IGRAPH_F77_SAVE integer np0;
    integer nbx=0;
    IGRAPH_F77_SAVE integer nev0;
    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *,
	    integer *);
    IGRAPH_F77_SAVE doublereal eps23;
    integer ierr;
    IGRAPH_F77_SAVE integer iter;
    doublereal temp;
    extern doublereal igraphdnrm2_(integer *, doublereal *, integer *);
    IGRAPH_F77_SAVE logical getv0, cnorm;
    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *,
	    doublereal *, integer *);
    IGRAPH_F77_SAVE integer nconv;
    extern /* Subroutine */ int igraphdmout_(integer *, integer *, integer *,
	    doublereal *, integer *, integer *, char *, ftnlen);
    IGRAPH_F77_SAVE logical initv;
    IGRAPH_F77_SAVE doublereal rnorm;
    real tmvbx=0;
    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *,
	    integer *, char *, ftnlen), igraphivout_(integer *, integer *, integer *
	    , integer *, char *, ftnlen), igraphdgetv0_(integer *, char *, integer *
	    , logical *, integer *, integer *, doublereal *, integer *,
	    doublereal *, doublereal *, integer *, doublereal *, integer *);
    extern doublereal igraphdlapy2_(doublereal *, doublereal *);
    integer mnaup2=0;
    real tnaup2=0;
    extern doublereal igraphdlamch_(char *);
    extern /* Subroutine */ int igraphdneigh_(doublereal *, integer *, doublereal *,
	     integer *, doublereal *, doublereal *, doublereal *, doublereal *
	    , integer *, doublereal *, integer *);
    IGRAPH_F77_SAVE integer nevbef;
    extern /* Subroutine */ int igrapharscnd_(real *);
    integer logfil=6, ndigit=-3;
    extern /* Subroutine */ int igraphdnaitr_(integer *, char *, integer *, integer
	    *, integer *, integer *, doublereal *, doublereal *, doublereal *,
	     integer *, doublereal *, integer *, integer *, doublereal *,
	    integer *);
    IGRAPH_F77_SAVE logical update;
    extern /* Subroutine */ int igraphdngets_(integer *, char *, integer *, integer
	    *, doublereal *, doublereal *, doublereal *, doublereal *,
	    doublereal *), igraphdnapps_(integer *, integer *, integer *,
	    doublereal *, doublereal *, doublereal *, integer *, doublereal *,
	     integer *, doublereal *, doublereal *, integer *, doublereal *,
	    doublereal *), igraphdnconv_(integer *, doublereal *, doublereal *,
	    doublereal *, doublereal *, integer *), igraphdsortc_(char *, logical *,
	     integer *, doublereal *, doublereal *, doublereal *);
    IGRAPH_F77_SAVE logical ushift;
    char wprime[2];
    IGRAPH_F77_SAVE integer msglvl;
    integer nptemp;
    IGRAPH_F77_SAVE integer numcnv, kplusp;


/*     %----------------------------------------------------%
       | Include files for debugging and timing information |
       %----------------------------------------------------%


       %------------------%
       | Scalar Arguments |
       %------------------%


       %-----------------%
       | Array Arguments |
       %-----------------%


       %------------%
       | Parameters |
       %------------%


       %---------------%
       | Local Scalars |
       %---------------%


       %-----------------------%
       | Local array arguments |
       %-----------------------%


       %----------------------%
       | External Subroutines |
       %----------------------%


       %--------------------%
       | External Functions |
       %--------------------%


       %---------------------%
       | Intrinsic Functions |
       %---------------------%


       %-----------------------%
       | Executable Statements |
       %-----------------------%

       Parameter adjustments */
    --workd;
    --resid;
    --workl;
    --bounds;
    --ritzi;
    --ritzr;
    v_dim1 = *ldv;
    v_offset = 1 + v_dim1;
    v -= v_offset;
    h_dim1 = *ldh;
    h_offset = 1 + h_dim1;
    h__ -= h_offset;
    q_dim1 = *ldq;
    q_offset = 1 + q_dim1;
    q -= q_offset;
    --ipntr;

    /* Function Body */
    if (*ido == 0) {

	igrapharscnd_(&t0);

	msglvl = mnaup2;

/*        %-------------------------------------%
          | Get the machine dependent constant. |
          %-------------------------------------% */

	eps23 = igraphdlamch_("Epsilon-Machine");
	eps23 = pow_dd(&eps23, &c_b3);

	nev0 = *nev;
	np0 = *np;

/*        %-------------------------------------%
          | kplusp is the bound on the largest  |
          |        Lanczos factorization built. |
          | nconv is the current number of      |
          |        "converged" eigenvlues.      |
          | iter is the counter on the current  |
          |      iteration step.                |
          %-------------------------------------% */

	kplusp = *nev + *np;
	nconv = 0;
	iter = 0;

/*        %---------------------------------------%
          | Set flags for computing the first NEV |
          | steps of the Arnoldi factorization.   |
          %---------------------------------------% */

	getv0 = TRUE_;
	update = FALSE_;
	ushift = FALSE_;
	cnorm = FALSE_;

	if (*info != 0) {

/*           %--------------------------------------------%
             | User provides the initial residual vector. |
             %--------------------------------------------% */

	    initv = TRUE_;
	    *info = 0;
	} else {
	    initv = FALSE_;
	}
    }

/*     %---------------------------------------------%
       | Get a possibly random starting vector and   |
       | force it into the range of the operator OP. |
       %---------------------------------------------%

   L10: */

    if (getv0) {
	igraphdgetv0_(ido, bmat, &c__1, &initv, n, &c__1, &v[v_offset], ldv, &resid[
		1], &rnorm, &ipntr[1], &workd[1], info);

	if (*ido != 99) {
	    goto L9000;
	}

	if (rnorm == 0.) {

/*           %-----------------------------------------%
             | The initial vector is zero. Error exit. |
             %-----------------------------------------% */

	    *info = -9;
	    goto L1100;
	}
	getv0 = FALSE_;
	*ido = 0;
    }

/*     %-----------------------------------%
       | Back from reverse communication : |
       | continue with update step         |
       %-----------------------------------% */

    if (update) {
	goto L20;
    }

/*     %-------------------------------------------%
       | Back from computing user specified shifts |
       %-------------------------------------------% */

    if (ushift) {
	goto L50;
    }

/*     %-------------------------------------%
       | Back from computing residual norm   |
       | at the end of the current iteration |
       %-------------------------------------% */

    if (cnorm) {
	goto L100;
    }

/*     %----------------------------------------------------------%
       | Compute the first NEV steps of the Arnoldi factorization |
       %----------------------------------------------------------% */

    igraphdnaitr_(ido, bmat, n, &c__0, nev, mode, &resid[1], &rnorm, &v[v_offset],
	    ldv, &h__[h_offset], ldh, &ipntr[1], &workd[1], info);

/*     %---------------------------------------------------%
       | ido .ne. 99 implies use of reverse communication  |
       | to compute operations involving OP and possibly B |
       %---------------------------------------------------% */

    if (*ido != 99) {
	goto L9000;
    }

    if (*info > 0) {
	*np = *info;
	*mxiter = iter;
	*info = -9999;
	goto L1200;
    }

/*     %--------------------------------------------------------------%
       |                                                              |
       |           M A I N  ARNOLDI  I T E R A T I O N  L O O P       |
       |           Each iteration implicitly restarts the Arnoldi     |
       |           factorization in place.                            |
       |                                                              |
       %--------------------------------------------------------------% */

L1000:

    ++iter;

    if (msglvl > 0) {
	igraphivout_(&logfil, &c__1, &iter, &ndigit, "_naup2: **** Start of major "
		"iteration number ****", (ftnlen)49);
    }

/*        %-----------------------------------------------------------%
          | Compute NP additional steps of the Arnoldi factorization. |
          | Adjust NP since NEV might have been updated by last call  |
          | to the shift application routine dnapps .                  |
          %-----------------------------------------------------------% */

    *np = kplusp - *nev;

    if (msglvl > 1) {
	igraphivout_(&logfil, &c__1, nev, &ndigit, "_naup2: The length of the curr"
		"ent Arnoldi factorization", (ftnlen)55);
	igraphivout_(&logfil, &c__1, np, &ndigit, "_naup2: Extend the Arnoldi fact"
		"orization by", (ftnlen)43);
    }

/*        %-----------------------------------------------------------%
          | Compute NP additional steps of the Arnoldi factorization. |
          %-----------------------------------------------------------% */

    *ido = 0;
L20:
    update = TRUE_;

    igraphdnaitr_(ido, bmat, n, nev, np, mode, &resid[1], &rnorm, &v[v_offset], ldv,
	     &h__[h_offset], ldh, &ipntr[1], &workd[1], info);

/*        %---------------------------------------------------%
          | ido .ne. 99 implies use of reverse communication  |
          | to compute operations involving OP and possibly B |
          %---------------------------------------------------% */

    if (*ido != 99) {
	goto L9000;
    }

    if (*info > 0) {
	*np = *info;
	*mxiter = iter;
	*info = -9999;
	goto L1200;
    }
    update = FALSE_;

    if (msglvl > 1) {
	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_naup2: Corresponding B-nor"
		"m of the residual", (ftnlen)44);
    }

/*        %--------------------------------------------------------%
          | Compute the eigenvalues and corresponding error bounds |
          | of the current upper Hessenberg matrix.                |
          %--------------------------------------------------------% */

    igraphdneigh_(&rnorm, &kplusp, &h__[h_offset], ldh, &ritzr[1], &ritzi[1], &
	    bounds[1], &q[q_offset], ldq, &workl[1], &ierr);

    if (ierr != 0) {
	*info = -8;
	goto L1200;
    }

/*        %----------------------------------------------------%
          | Make a copy of eigenvalues and corresponding error |
          | bounds obtained from dneigh .                       |
          %----------------------------------------------------%

   Computing 2nd power */
    i__1 = kplusp;
    igraphdcopy_(&kplusp, &ritzr[1], &c__1, &workl[i__1 * i__1 + 1], &c__1);
/* Computing 2nd power */
    i__1 = kplusp;
    igraphdcopy_(&kplusp, &ritzi[1], &c__1, &workl[i__1 * i__1 + kplusp + 1], &c__1)
	    ;
/* Computing 2nd power */
    i__1 = kplusp;
    igraphdcopy_(&kplusp, &bounds[1], &c__1, &workl[i__1 * i__1 + (kplusp << 1) + 1]
	    , &c__1);

/*        %---------------------------------------------------%
          | Select the wanted Ritz values and their bounds    |
          | to be used in the convergence test.               |
          | The wanted part of the spectrum and corresponding |
          | error bounds are in the last NEV loc. of RITZR,   |
          | RITZI and BOUNDS respectively. The variables NEV  |
          | and NP may be updated if the NEV-th wanted Ritz   |
          | value has a non zero imaginary part. In this case |
          | NEV is increased by one and NP decreased by one.  |
          | NOTE: The last two arguments of dngets  are no     |
          | longer used as of version 2.1.                    |
          %---------------------------------------------------% */

    *nev = nev0;
    *np = np0;
    numcnv = *nev;
    igraphdngets_(ishift, which, nev, np, &ritzr[1], &ritzi[1], &bounds[1], &workl[
	    1], &workl[*np + 1]);
    if (*nev == nev0 + 1) {
	numcnv = nev0 + 1;
    }

/*        %-------------------%
          | Convergence test. |
          %-------------------% */

    igraphdcopy_(nev, &bounds[*np + 1], &c__1, &workl[(*np << 1) + 1], &c__1);
    igraphdnconv_(nev, &ritzr[*np + 1], &ritzi[*np + 1], &workl[(*np << 1) + 1],
	    tol, &nconv);

    if (msglvl > 2) {
	kp[0] = *nev;
	kp[1] = *np;
	kp[2] = numcnv;
	kp[3] = nconv;
	igraphivout_(&logfil, &c__4, kp, &ndigit, "_naup2: NEV, NP, NUMCNV, NCONV "
		"are", (ftnlen)34);
	igraphdvout_(&logfil, &kplusp, &ritzr[1], &ndigit, "_naup2: Real part of t"
		"he eigenvalues of H", (ftnlen)41);
	igraphdvout_(&logfil, &kplusp, &ritzi[1], &ndigit, "_naup2: Imaginary part"
		" of the eigenvalues of H", (ftnlen)46);
	igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_naup2: Ritz estimate"
		"s of the current NCV Ritz values", (ftnlen)53);
    }

/*        %---------------------------------------------------------%
          | Count the number of unwanted Ritz values that have zero |
          | Ritz estimates. If any Ritz estimates are equal to zero |
          | then a leading block of H of order equal to at least    |
          | the number of Ritz values with zero Ritz estimates has  |
          | split off. None of these Ritz values may be removed by  |
          | shifting. Decrease NP the number of shifts to apply. If |
          | no shifts may be applied, then prepare to exit          |
          %---------------------------------------------------------% */

    nptemp = *np;
    i__1 = nptemp;
    for (j = 1; j <= i__1; ++j) {
	if (bounds[j] == 0.) {
	    --(*np);
	    ++(*nev);
	}
/* L30: */
    }

    if (nconv >= numcnv || iter > *mxiter || *np == 0) {

	if (msglvl > 4) {
/* Computing 2nd power */
	    i__1 = kplusp;
	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + 1], &ndigit, "_nau"
		    "p2: Real part of the eig computed by _neigh:", (ftnlen)48)
		    ;
/* Computing 2nd power */
	    i__1 = kplusp;
	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + kplusp + 1], &
		    ndigit, "_naup2: Imag part of the eig computed by _neigh:"
		    , (ftnlen)48);
/* Computing 2nd power */
	    i__1 = kplusp;
	    igraphdvout_(&logfil, &kplusp, &workl[i__1 * i__1 + (kplusp << 1) + 1],
		    &ndigit, "_naup2: Ritz eistmates computed by _neigh:", (
		    ftnlen)42);
	}

/*           %------------------------------------------------%
             | Prepare to exit. Put the converged Ritz values |
             | and corresponding bounds in RITZ(1:NCONV) and  |
             | BOUNDS(1:NCONV) respectively. Then sort. Be    |
             | careful when NCONV > NP                        |
             %------------------------------------------------%

             %------------------------------------------%
             |  Use h( 3,1 ) as storage to communicate  |
             |  rnorm to _neupd if needed               |
             %------------------------------------------% */
	h__[h_dim1 + 3] = rnorm;

/*           %----------------------------------------------%
             | To be consistent with dngets , we first do a  |
             | pre-processing sort in order to keep complex |
             | conjugate pairs together.  This is similar   |
             | to the pre-processing sort used in dngets     |
             | except that the sort is done in the opposite |
             | order.                                       |
             %----------------------------------------------% */

	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SR", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
	}

	igraphdsortc_(wprime, &c_true, &kplusp, &ritzr[1], &ritzi[1], &bounds[1]);

/*           %----------------------------------------------%
             | Now sort Ritz values so that converged Ritz  |
             | values appear within the first NEV locations |
             | of ritzr, ritzi and bounds, and the most     |
             | desired one appears at the front.            |
             %----------------------------------------------% */

	if (s_cmp(which, "LM", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SM", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SM", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LM", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "LR", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SR", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SR", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "LI", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "SI", (ftnlen)2, (ftnlen)2);
	}
	if (s_cmp(which, "SI", (ftnlen)2, (ftnlen)2) == 0) {
	    s_copy(wprime, "LI", (ftnlen)2, (ftnlen)2);
	}

	igraphdsortc_(wprime, &c_true, &kplusp, &ritzr[1], &ritzi[1], &bounds[1]);

/*           %--------------------------------------------------%
             | Scale the Ritz estimate of each Ritz value       |
             | by 1 / max(eps23,magnitude of the Ritz value).   |
             %--------------------------------------------------% */

	i__1 = numcnv;
	for (j = 1; j <= i__1; ++j) {
/* Computing MAX */
	    d__1 = eps23, d__2 = igraphdlapy2_(&ritzr[j], &ritzi[j]);
	    temp = max(d__1,d__2);
	    bounds[j] /= temp;
/* L35: */
	}

/*           %----------------------------------------------------%
             | Sort the Ritz values according to the scaled Ritz  |
             | esitmates.  This will push all the converged ones  |
             | towards the front of ritzr, ritzi, bounds          |
             | (in the case when NCONV < NEV.)                    |
             %----------------------------------------------------% */

	s_copy(wprime, "LR", (ftnlen)2, (ftnlen)2);
	igraphdsortc_(wprime, &c_true, &numcnv, &bounds[1], &ritzr[1], &ritzi[1]);

/*           %----------------------------------------------%
             | Scale the Ritz estimate back to its original |
             | value.                                       |
             %----------------------------------------------% */

	i__1 = numcnv;
	for (j = 1; j <= i__1; ++j) {
/* Computing MAX */
	    d__1 = eps23, d__2 = igraphdlapy2_(&ritzr[j], &ritzi[j]);
	    temp = max(d__1,d__2);
	    bounds[j] *= temp;
/* L40: */
	}

/*           %------------------------------------------------%
             | Sort the converged Ritz values again so that   |
             | the "threshold" value appears at the front of  |
             | ritzr, ritzi and bound.                        |
             %------------------------------------------------% */

	igraphdsortc_(which, &c_true, &nconv, &ritzr[1], &ritzi[1], &bounds[1]);

	if (msglvl > 1) {
	    igraphdvout_(&logfil, &kplusp, &ritzr[1], &ndigit, "_naup2: Sorted rea"
		    "l part of the eigenvalues", (ftnlen)43);
	    igraphdvout_(&logfil, &kplusp, &ritzi[1], &ndigit, "_naup2: Sorted ima"
		    "ginary part of the eigenvalues", (ftnlen)48);
	    igraphdvout_(&logfil, &kplusp, &bounds[1], &ndigit, "_naup2: Sorted ri"
		    "tz estimates.", (ftnlen)30);
	}

/*           %------------------------------------%
             | Max iterations have been exceeded. |
             %------------------------------------% */

	if (iter > *mxiter && nconv < numcnv) {
	    *info = 1;
	}

/*           %---------------------%
             | No shifts to apply. |
             %---------------------% */

	if (*np == 0 && nconv < numcnv) {
	    *info = 2;
	}

	*np = nconv;
	goto L1100;

    } else if (nconv < numcnv && *ishift == 1) {

/*           %-------------------------------------------------%
             | Do not have all the requested eigenvalues yet.  |
             | To prevent possible stagnation, adjust the size |
             | of NEV.                                         |
             %-------------------------------------------------% */

	nevbef = *nev;
/* Computing MIN */
	i__1 = nconv, i__2 = *np / 2;
	*nev += min(i__1,i__2);
	if (*nev == 1 && kplusp >= 6) {
	    *nev = kplusp / 2;
	} else if (*nev == 1 && kplusp > 3) {
	    *nev = 2;
	}
/*           %---- Scipy fix ------------------------------------------------
             | We must keep nev below this value, as otherwise we can get
             | np == 0 (note that dngets below can bump nev by 1). If np == 0,
             | the next call to `dnaitr` will write out-of-bounds.
             | */
	if (*nev > kplusp - 2) {
	    *nev = kplusp - 2;
	}
/*           |
             %---- Scipy fix end -------------------------------------------- */

	*np = kplusp - *nev;

/*           %---------------------------------------%
             | If the size of NEV was just increased |
             | resort the eigenvalues.               |
             %---------------------------------------% */

	if (nevbef < *nev) {
	    igraphdngets_(ishift, which, nev, np, &ritzr[1], &ritzi[1], &bounds[1],
		    &workl[1], &workl[*np + 1]);
	}

    }

    if (msglvl > 0) {
	igraphivout_(&logfil, &c__1, &nconv, &ndigit, "_naup2: no. of \"converge"
		"d\" Ritz values at this iter.", (ftnlen)52);
	if (msglvl > 1) {
	    kp[0] = *nev;
	    kp[1] = *np;
	    igraphivout_(&logfil, &c__2, kp, &ndigit, "_naup2: NEV and NP are", (
		    ftnlen)22);
	    igraphdvout_(&logfil, nev, &ritzr[*np + 1], &ndigit, "_naup2: \"wante"
		    "d\" Ritz values -- real part", (ftnlen)41);
	    igraphdvout_(&logfil, nev, &ritzi[*np + 1], &ndigit, "_naup2: \"wante"
		    "d\" Ritz values -- imag part", (ftnlen)41);
	    igraphdvout_(&logfil, nev, &bounds[*np + 1], &ndigit, "_naup2: Ritz es"
		    "timates of the \"wanted\" values ", (ftnlen)46);
	}
    }

    if (*ishift == 0) {

/*           %-------------------------------------------------------%
             | User specified shifts: reverse communication to       |
             | compute the shifts. They are returned in the first    |
             | 2*NP locations of WORKL.                              |
             %-------------------------------------------------------% */

	ushift = TRUE_;
	*ido = 3;
	goto L9000;
    }

L50:

/*        %------------------------------------%
          | Back from reverse communication;   |
          | User specified shifts are returned |
          | in WORKL(1:2*NP)                   |
          %------------------------------------% */

    ushift = FALSE_;

    if (*ishift == 0) {

/*            %----------------------------------%
              | Move the NP shifts from WORKL to |
              | RITZR, RITZI to free up WORKL    |
              | for non-exact shift case.        |
              %----------------------------------% */

	igraphdcopy_(np, &workl[1], &c__1, &ritzr[1], &c__1);
	igraphdcopy_(np, &workl[*np + 1], &c__1, &ritzi[1], &c__1);
    }

    if (msglvl > 2) {
	igraphivout_(&logfil, &c__1, np, &ndigit, "_naup2: The number of shifts to"
		" apply ", (ftnlen)38);
	igraphdvout_(&logfil, np, &ritzr[1], &ndigit, "_naup2: Real part of the sh"
		"ifts", (ftnlen)31);
	igraphdvout_(&logfil, np, &ritzi[1], &ndigit, "_naup2: Imaginary part of t"
		"he shifts", (ftnlen)36);
	if (*ishift == 1) {
	    igraphdvout_(&logfil, np, &bounds[1], &ndigit, "_naup2: Ritz estimates"
		    " of the shifts", (ftnlen)36);
	}
    }

/*        %---------------------------------------------------------%
          | Apply the NP implicit shifts by QR bulge chasing.       |
          | Each shift is applied to the whole upper Hessenberg     |
          | matrix H.                                               |
          | The first 2*N locations of WORKD are used as workspace. |
          %---------------------------------------------------------% */

    igraphdnapps_(n, nev, np, &ritzr[1], &ritzi[1], &v[v_offset], ldv, &h__[
	    h_offset], ldh, &resid[1], &q[q_offset], ldq, &workl[1], &workd[1]
	    );

/*        %---------------------------------------------%
          | Compute the B-norm of the updated residual. |
          | Keep B*RESID in WORKD(1:N) to be used in    |
          | the first step of the next call to dnaitr .  |
          %---------------------------------------------% */

    cnorm = TRUE_;
    igrapharscnd_(&t2);
    if (*(unsigned char *)bmat == 'G') {
	++nbx;
	igraphdcopy_(n, &resid[1], &c__1, &workd[*n + 1], &c__1);
	ipntr[1] = *n + 1;
	ipntr[2] = 1;
	*ido = 2;

/*           %----------------------------------%
             | Exit in order to compute B*RESID |
             %----------------------------------% */

	goto L9000;
    } else if (*(unsigned char *)bmat == 'I') {
	igraphdcopy_(n, &resid[1], &c__1, &workd[1], &c__1);
    }

L100:

/*        %----------------------------------%
          | Back from reverse communication; |
          | WORKD(1:N) := B*RESID            |
          %----------------------------------% */

    if (*(unsigned char *)bmat == 'G') {
	igrapharscnd_(&t3);
	tmvbx += t3 - t2;
    }

    if (*(unsigned char *)bmat == 'G') {
	rnorm = igraphddot_(n, &resid[1], &c__1, &workd[1], &c__1);
	rnorm = sqrt((abs(rnorm)));
    } else if (*(unsigned char *)bmat == 'I') {
	rnorm = igraphdnrm2_(n, &resid[1], &c__1);
    }
    cnorm = FALSE_;

    if (msglvl > 2) {
	igraphdvout_(&logfil, &c__1, &rnorm, &ndigit, "_naup2: B-norm of residual "
		"for compressed factorization", (ftnlen)55);
	igraphdmout_(&logfil, nev, nev, &h__[h_offset], ldh, &ndigit, "_naup2: Com"
		"pressed upper Hessenberg matrix H", (ftnlen)44);
    }

    goto L1000;

/*     %---------------------------------------------------------------%
       |                                                               |
       |  E N D     O F     M A I N     I T E R A T I O N     L O O P  |
       |                                                               |
       %---------------------------------------------------------------% */

L1100:

    *mxiter = iter;
    *nev = numcnv;

L1200:
    *ido = 99;

/*     %------------%
       | Error Exit |
       %------------% */

    igrapharscnd_(&t1);
    tnaup2 = t1 - t0;

L9000:

/*     %---------------%
       | End of dnaup2  |
       %---------------% */

    return 0;
} /* igraphdnaup2_ */

