/* ========================================================================== */
/* === Source/napheap.c ===================================================== */
/* ========================================================================== */

/*
   =========================================================================
   ============================== NAPHEAP ==================================
   =========================================================================

       ________________________________________________________________
      |Solve a separable convex quadratic knapsack problem of the form:|
      |                                                                |
      | min .5x'Dx - y'x  subject to  lo <= x <= hi, blo <= a'x <= bhi |
      |                                                                |
      |       where lo and hi are vectors, blo and bhi are scalars,    |
      |       and D is a diagonal matrix with nonnegative diagonal.    |
      |                                                                |
      |                 Copyright by Timothy A. Davis                  |
      |                              William W. Hager                  |
      |                              James T. Hungerford               |
      |                                                                |
      |          http://www.math.ufl.edu/~hager/papers/Software        |
      |                                                                |
      |  Disclaimer: The views expressed are those of the authors and  |
      |              do not reflect the official policy or position of |
      |              the Department of Defense or the U.S. Government. |
      |                                                                |
      |      Approved for Public Release, Distribution Unlimited       |
      |________________________________________________________________|

    The constraints are rewritten as

               lo <= x <= hi,    blo <= b <= bhi,    a'x = b

    The code solves the dual problem obtained by introducing
    a multiplier lambda for the constraint a'x = b.  The dual function is

    L(lambda) = inf {.5x'Dx - y'x + lambda (a'x - b):
                                 lo <= x <= hi, blo <= b <= bhi}

    The dual function is concave, and the solution to the original (primal)
    problem can be constructed from the maximizer of the dual function.
    If blo < bhi, then there is a discontinuity at lambda = 0.  D is a
    diagonal matrix, and if d = diag(D) contains zeros, there could be
    additional points of discontinuity.  The algorithm iterates on lambda
    until 0 lies in the subdifferential of L(lambda).  The optimal x is
    constructed from the minimizers of the dual function.  Three algorithms
    are implemented: a break point searching algorithm, a variable fixing
    algorithm, and a Newton/secant algorithm.  A starting guess for the
    optimal multiplier can be provided.  If the user does not have a good
    starting guess, at most Parm->K (default 20) iterations of a Newton-type
    algorithm are used to generate a starting guess. The Newton-type method
    terminates when the root is bracketed.

    By default, Newton's method is used for the startup (Parm->newton =
    TRUE).  Set Parm->newton to FALSE to choose the variable fixing
    algorithm for startup. After the startup iterations, the breakpoint
    algorithm is used to compute the final solution. When Newton's method is
    used for the startup, all entries of d must be positive (otherwise an error
    is returned), so to solve problems with zeros in d, you must set
    Parm->newton to FALSE.  No value of d can be negative, for any method.

    The user can either provide work arrays or let the code malloc work arrays.
    The necessary size for the work arrays depends on the choice of the
    algorithm, as can be seen in the memory allocation routine.  The most
    memory that the code will require is an NAPINT work array of size 4*n+2
    and a real work array of size 5*n where n is the problem dimension.

    The default parameter values used by the software are given in the
    napheap_default routine.  To alter the default parameter values, the
    user can first initialize the parameters to their default values using
    napheap_default, make any changes to the values in the parameter
    structure, and provide the updated parameter structure as an input to the
    napheap code. Note that TRUE = 1 and FALSE = 0.

    The code records the number of iterations for either the variable fixing or
    Newton method, and the number of break points that are passed through
    during the solution process.  These statistics are returned when the user
    provides a nonnull structure for the statistics argument of the code.  The
    statistics and parameters can be printed with napheap_print_stat and
    napheap_print_parms.

    If the user wishes to override the default definition of infinity
    given in Include/napheap.h, modify the OPTFLAGS as explained in
    Lib/napheap.mk.
       ________________________________________________________________
      |This program 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 2 of  |
      |the License, or (at your option) any later version.             |
      |This program 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 this program; if not, write to the Free      |
      |Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
      |MA  02110-1301  USA                                             |
      |________________________________________________________________|

      Alternative licenses are also available.  Please contact William Hager
      for details.

      Reference:
         T. A. Davis, W. W. Hager, and J. T. Hungerford, An Efficient
         Hybrid Algorithm for the Separable Convex Quadratic Knapsack Problem,
         see Doc/napheap_paper.pdf
*/

#include "napheap_internal.h"

/* for debugging */
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>

/* ========================================================================== */
/* === user-callable functions ============================================== */
/* ========================================================================== */

/* There are only four user-callable functions:
    napheap_default  - sets default parameters for napheap
    napheap          - solves a separable convex quadratic knapsack problem
    napheap_print    - print napheap parameters and statistics
    naptest          - exhaustive test of napheap code (in Test directory)
*/

/* ========================================================================== */
/* === napheap  ============================================================= */
/* ========================================================================== */

int napheap  /* Return status of solution process. To determine the status, use
                napheap_print_status (napdata) */
(
    NAPdata *napdata
)
{
    int    status ;
    NAPINT it, k, nk, nuf, nkf ;

    status = NAPHEAP_STATUS_OK ;   /* default status */
    NAPINT const n = napdata->n ;  /* problem dimension */
    if ( n == EMPTY )
    {
        status = NAPHEAP_STATUS_INVALID_N ;
        napdata->Parm->PrintStat = FALSE ;
        napdata->Stat->kerror = n ;
        return (nap_wrapup (status, napdata, napdata->lambda)) ;
    }

    /* if y is NULL, then it is treated as zero */
    if ( napdata->y == NULL )
    {
        napdata->y = (NAPFLOAT *) napheap_malloc (&status, n, sizeof(NAPFLOAT));
        if ( status == NAPHEAP_STATUS_OUT_OF_MEMORY )
        {
            napdata->Parm->PrintStat = FALSE ;
            return (nap_wrapup (status, napdata, napdata->lambda)) ;
        }
        napdata->y_created = napdata->y ;
        for (k = 0; k < n; k++) napdata->y [k] = NAPZERO ;
    }

    /* create the solution array if the user did not provide one */
    if ( napdata->x == NULL )
    {
        napdata->x = (NAPFLOAT *) napheap_malloc (&status, n, sizeof(NAPFLOAT));
        if ( status == NAPHEAP_STATUS_OUT_OF_MEMORY )
        {
            napdata->Parm->PrintStat = FALSE ;
            return (nap_wrapup (status, napdata, napdata->lambda)) ;
        }
        napdata->x_created = napdata->x ;
    }

    /* grab the problem data */
    NAPFLOAT        *x = napdata->x ;      /* solution */
    NAPFLOAT    lambda = napdata->lambda ; /* linear constraint multiplier */
    NAPFLOAT const  *y = napdata->y ;      /* linear cost vector */
    NAPFLOAT const  *d = napdata->d ;      /* diagonal of objective Hessian */
    NAPFLOAT const  *a = napdata->a ;      /* linear constraint vector */
    NAPFLOAT const *lo = napdata->lo ;     /* lower bounds for x */
    NAPFLOAT const *hi = napdata->hi ;     /* upper bounds for x */
    NAPstat      *Stat = napdata->Stat ;   /* structure for statistics */
    NAPparm      *Parm = napdata->Parm ;   /* structure for parameters */
    NAPFLOAT    *xWork = napdata->xWork ;  /* NULL = code creates NAPFLOAT mem*/
    NAPINT      *iWork = napdata->iWork ;  /* NULL = code creates NAPINT mem */

    /* NOTE: napdata->blo and napdata->bhi are extracted later,
             after napheap_check */

    /* data from a prior run if it exists */
    NAPFLOAT const akakdk = napdata->akakdk ;

    /* internal variable used in the code */
    int use_newton ; /* TRUE if starting guess is Newton iteration */
    int goright ;    /* TRUE if optimal multiplier to right of current lambda */
    int crossed ;    /* TRUE when iterate crosses root */
    /* Rout and Lout are only used when a diagonal element vanishes */
    int Rout ;       /* becomes FALSE when optimal lambda < lambdaR and hence,
                        lambdaR cannot be optimal */
    int Lout ;       /* becomes FALSE when optimal lambda > lambdaL and hence,
                        lambdaL cannot be optimal */
    int K ;          /* number of iterations in Newton's or variable fixing
                        methods */
    int k_gt_1 ;     /* TRUE if K > 1 */
    int recompute_slope ;     /* TRUE if slope at current lambda not known */
    NAPFLOAT maxax, minax ;
    NAPFLOAT *ada = NULL ;      /* size n, ada[j] == aj*aj */
    NAPFLOAT *ady = NULL ;      /* size n, ady[j] == aj*yj */
    NAPFLOAT *ad = NULL ;       /* size n, ad[j] = aj/dj */
    NAPFLOAT *ay = NULL ;       /* size n, ay[j] = yj/aj */
    /* breakpts [j] is defined only when j is in the list of undetermined
       variables.  It is the first break point between the current lambda
       and the root */
    NAPFLOAT *breakpts = NULL ; /* size n */
    NAPFLOAT *breaknext = NULL ;/* size n, stores next break point */
    NAPFLOAT *br_hi = NULL ;    /* size n. br_hi[j] hi break pt for x[j] */
    NAPFLOAT *br_lo = NULL ;    /* size n, br_lo[j] lo break pt for x[j] */
    NAPFLOAT b ;                /* a'x = b */
    NAPFLOAT domlo ;            /* lower bound for domain of dual function */
    NAPFLOAT domhi ;            /* upper bound for domain of dual function */
    NAPFLOAT slope ;            /* slope at lambda, exclude subdiff. term */
    NAPFLOAT slopelo ;          /* lower subdifferential at lambda */
    NAPFLOAT slopehi ;          /* upper subdifferential at lambda */
    NAPFLOAT slope0 ;           /* slope at lambda = 0 excluding subdiff term */
    NAPFLOAT slope0lo ;         /* lower subdifferential at lambda = 0 */
    NAPFLOAT slope0hi ;         /* upper subdifferential at lambda = 0 */
    NAPFLOAT prevlambda ;       /* value of lambda in previous iteration */
    NAPFLOAT pprevlambda ;      /* value of lambda in pre-previous iteration */
    NAPFLOAT lambdaL ;          /* lower bound for optimal multiplier */
    NAPFLOAT lambdaR ;          /* upper bound for optimal multiplier */
    NAPFLOAT dL ;               /* slope at lambdaL */
    NAPFLOAT dR ;               /* slope at lambdaR */
    NAPFLOAT prevslope ;        /* slope in the previous iteration */
    NAPFLOAT pprevslope ;       /* slope in the pre-previous iteration */
    int  prevstep;              /* type of step at each iteration */
    NAPFLOAT num ;              /* numerator of variable fixing ratio */
    NAPFLOAT den ;              /* denominator of variable fixing ratio */
    NAPFLOAT numFV ;            /* initial num of variable fixing ratio */
    NAPFLOAT denFV ;            /* initial den of variable fixing ratio */

    NAPINT *uf = NULL ;         /* size n, unfixed variables */
    NAPINT *kf = NULL ;         /* size n, known free variables */
    NAPINT *free_heap = NULL ;  /* size n+1, heap of free variables */
    NAPINT *bound_heap = NULL ; /* size n+1, heap of bound variables */
    NAPINT *iwork ;             /* internal NAPINT workspace */
    NAPFLOAT *xw2 = NULL ;      /* internal NAPFLOAT workspace */

    int start_napsearch;        /* TRUE when break point search used */
    int start_napsearch_next ;  /* TRUE if napsearch starts next iteration */

    NAPINT nnewton ;            /* number of newton steps taken */
    NAPINT nsecant ;            /* number of secant steps taken */
    NAPINT nvarfix ;            /* number of vf steps taken during loop
                                   iterations (these are slow steps) */
    NAPINT nbound ;             /* number of indices in bound heap */
    NAPINT nfree ;              /* number of indices in free heap */
    /* use_lambda is TRUE is the user provides a starting guess for the
       multiplier associated with the constraint blo <= a'x <= bhi */
    int use_lambda = ( lambda >= NAPINF ) ? FALSE : TRUE ;

    /* ---------------------------------------------------------------------- */
    /*  Initialization and checks */
    /* ---------------------------------------------------------------------- */
    if ( Parm == NULL )
    {
        status = NAPHEAP_STATUS_MISSING_PARM ;
        return (nap_wrapup (status, napdata, lambda)) ;
    }
    if ( Stat == NULL )
    {
        status = NAPHEAP_STATUS_MISSING_STAT ;
        return (nap_wrapup (status, napdata, lambda)) ;
    }
    if ( Parm->PrintParm )
    {
        napheap_print_parm (napdata) ;
    }

    int const use_prior_data = Parm->use_prior_data ;

    /* when using prior data, add statistics to prior totals,
       when not using prior data, initialize statistics to 0 */
    if ( !use_prior_data )
    {
        Stat->kerror  = 0 ;
        Stat->lobad   = 0 ;
        Stat->hibad   = 0 ;
        Stat->dbad    = 0 ;
        Stat->nkf     = 0 ;
        Stat->nfree   = 0 ;
        Stat->nbound  = 0 ;
        Stat->nbrks   = 0 ;
        Stat->nrefine = 0 ;
        Stat->nvarfix = 0 ;
        Stat->nnewton = 0 ;
        Stat->nsecant = 0 ;
    }

    /* check for consistency in the parameter values */
    if ( (Parm->d_is_zero == TRUE) && (Parm->d_is_one == TRUE) )
    {
        status = NAPHEAP_STATUS_CONFLICTING_PARM_D ;
        return (nap_wrapup (status, napdata, lambda)) ;
    }
    if ( (Parm->d_is_one == FALSE) && (Parm->d_is_zero == FALSE) &&
         (d == NULL) )
    {
        status = NAPHEAP_STATUS_CONFLICTING_PARM_D ;
        return (nap_wrapup (status, napdata, lambda)) ;
    }

    /* If lo == NULL, then loExists is always FALSE (lo = -INF), otherwise
       loExists = Parm->loExists */
    const int loExists = (lo == NULL) ? FALSE : Parm->loExists ;

    /* If hi == NULL, then hiExists is always FALSE (hi = INF), otherwise
       hiExists = Parm->hiExists */
    const int hiExists = (hi == NULL) ? FALSE : Parm->hiExists ;

    const int lohiExist = (loExists && hiExists) ;

    /* d_is_zero is TRUE if entries in d are all zero (input d is ignored).
       if d is NULL, then it is treated as identically zero. */
    const int d_is_zero = (d == NULL) ? TRUE : Parm->d_is_zero ;

    /* d_is_one is TRUE if entries in d are all one (input d is ignored) */
    const int d_is_one = Parm->d_is_one ;

    /* d_is_pos TRUE if d is identically 1 or all entries in d are positive.
       When d_is_pos is FALSE, there could be both zero and positive entries
       in d. */
    if ( d_is_zero == TRUE ) k = FALSE ;
    else                     k = Parm->d_is_pos ;
    const int d_is_pos = (d_is_one) ? TRUE : k ;

    /* check bounds and d if Parm->check is TRUE */
    if ( Parm->check )
    {
        /* Note: if Parm->check is false, then blo is permitted to be larger
           than bhi,  and we silently swap the two bounds.  However, when
           Parm->check is true, this case generates an error, since it might
           be a mistake on the part of the user.  */
        if ( napdata->blo > napdata->bhi )
        {
            status = NAPHEAP_STATUS_INVALID_B ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }
        for (k = 0; k < n; k++)
        {
            if ( d_is_pos || !d_is_zero )
            {
                if ( (d [k] < NAPZERO) || ((d [k] == NAPZERO) && d_is_pos) )
                {
                    status = NAPHEAP_STATUS_INVALID_D ;
                    Stat->kerror = k ;
                    Stat->dbad = d [k] ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }
            }
            if ( lohiExist && (lo [k] > hi [k]) )
            {
                /* invalid problem */
                status = NAPHEAP_STATUS_INVALID_BOUNDS ;
                Stat->kerror = k ;
                Stat->lobad = lo [k] ;
                Stat->hibad = hi [k] ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
        }
    }

    /* switch bounds if napdata->blo > napdata->bhi */
    NAPFLOAT const blo =
                   (napdata->blo > napdata->bhi) ? napdata->bhi : napdata->blo ;
    NAPFLOAT const bhi =
                   (napdata->blo > napdata->bhi) ? napdata->blo : napdata->bhi ;

    status = NAPHEAP_STATUS_OK ;   /* default status */

    /* ---------------------------------------------------------------------- */
    /* check for basic errors */
    /* ---------------------------------------------------------------------- */
    if (n == 0)
    {
        /* empty problem, do nothing */
        return (nap_wrapup (status, napdata, lambda)) ;
    }

    /* ---------------------------------------------------------------------- */
    /* in some cases, the equality constraint can be ignored */
    /* ---------------------------------------------------------------------- */
    if ( (a == NULL) || (Parm->Aexists == FALSE)
                     || ((blo <= -NAPINF) && (bhi >= NAPINF)) )
    {
        for (k = 0; k < n; k++)
        {
            NAPFLOAT t ;
            const NAPFLOAT yk = y [k] ;
            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
            const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
            if ( (d_is_zero == TRUE) || (d [k] == NAPZERO) )
            {
                if ( yk < NAPZERO )
                {
                    if ( lok > -NAPINF )
                    {
                        t = lok ;
                    }
                    else
                    {
                        t = -NAPINF ;
                        status = NAPHEAP_STATUS_UNBOUNDED ;
                    }
                }
                else if ( yk > NAPZERO )
                {
                    if ( hik < NAPINF )
                    {
                        t = hik ;
                    }
                    else
                    {
                        t = NAPINF ;
                        status = NAPHEAP_STATUS_UNBOUNDED ;
                    }
                }
                else if ( lok > -NAPINF )
                {
                    t = lok ;
                }
                else if ( hik < NAPINF )
                {
                    t = hik ;
                }
                else
                {
                    t = NAPZERO ;
                }
            }
            else /* d [k] > 0 */
            {
                t = (d_is_one) ? yk : yk/d [k] ;
                if ( t < lok )
                {
                    t = lok ;
                }
                else if ( t > hik )
                {
                    t = hik ;
                }
            }
            x [k] = t ;
        }
        /* status is NAPHEAP_STATUS_OK or NAPHEAP_STATUS_UNBOUNDED */
        ASSERT (status == NAPHEAP_STATUS_OK
             || status == NAPHEAP_STATUS_UNBOUNDED ) ;
        return (nap_wrapup (status, napdata, NAPZERO)) ;
    }

    const int newton = Parm->newton ;
    K = Parm->K ;
    if ( K < 0 ) K = 0; /* silently treat this as K = 0 */

    if ( !d_is_pos && newton )
    {
        /* Newton's method requires all (d>0). !d_is_pos is an error when
           Newton's method is specified. */
        status = NAPHEAP_STATUS_INVALID_NEWTON ;
        return (nap_wrapup (status, napdata, lambda)) ;
    }

    /* ---------------------------------------------------------------------- */
    /* initialize parameters */
    /* ---------------------------------------------------------------------- */

    /* use_lambda is TRUE if starting lambda is provided */
    if ( use_lambda && (lambda == NAPZERO) && (blo < bhi) )
    {
        use_lambda = FALSE ; /* slope at lambda = 0 is always evaluated */
    }

    /* ---------------------------------------------------------------------- */
    /* allocate NAPINT workspace */
    /* ---------------------------------------------------------------------- */

    if ( use_prior_data == TRUE )
    {
        iwork = iWork ;
    }
    else if ( iWork == NULL ) /* create memory if it is not provided by user */
    {
        iwork = (NAPINT *) napheap_malloc (&status, (4*n+2), sizeof (NAPINT)) ;
        /* Need space for uf, kf, free_heap, and bound_heap.  uf has size n
           while the heaps have size n+1: heap [0], heap [1], ... , heap [n] */
        if ( status ==  NAPHEAP_STATUS_OUT_OF_MEMORY )
        {
            return (nap_wrapup (status, napdata, lambda)) ;
        }
        napdata->iWork_created = napdata->iWork = iwork ;
    }
    else
    {
        /* use the user-provided workspace, iWork */
        iwork = iWork ;
    }

    /* assign pointers to NAPINT work arrays */
    uf = iwork ; iwork += n ;               /* uf, size n */
    kf = iwork ; iwork += n ;               /* kf, size n */
    bound_heap = iwork ; iwork += (n+1) ;   /* bound_heap, size n+1 */
    free_heap = iwork ;  iwork += (n+1) ;   /* free_heap, size n+1 */


    /* ---------------------------------------------------------------------- */
    /* allocate NAPFLOAT workspace */
    /* ---------------------------------------------------------------------- */

    if ( (K == 0) || d_is_pos )
    {
        if ( d_is_one )
        {
            /* 3n workspace */
            status = nap_work (n, xWork, &xw2,
                NULL, &ay, NULL,  NULL, &breakpts, &breaknext) ;
        }
        else
        {
            /* 4n workspace */
            status = nap_work (n, xWork, &xw2,
                &ad, &ay, NULL,  NULL, &breakpts, &breaknext) ;
        }
    }
    else if ( !d_is_zero )
    {
        /* 5n workspace */
        status = nap_work (n, xWork, &xw2,
            &ada, &ady, &br_hi, &br_lo, &breakpts, NULL);
    }
    else if ( K > 1 ) /* d_is_zero and K > 1 */
    {
        /* 3n workspace */
        status = nap_work (n, xWork, &xw2,
            &ada, &ady, NULL,  NULL, &breakpts, NULL) ;
    }
    else    /* d_is_zero and K = 1 */
    {
        /* 1n workspace */
        status = nap_work (n, xWork, &xw2,
            NULL, NULL, NULL,  NULL, &breakpts, NULL) ;
    }
    if (status != NAPHEAP_STATUS_OK)
    {
        return (nap_wrapup (status, napdata, lambda)) ;
    }
    /* if nap_work created some memory, then save pointer in napdata */
    if ( xw2 != NULL )
    {
        napdata->xWork_created = napdata->xWork = xw2 ;
    }

    /* ---------------------------------------------------------------------- */
    /* remaining initializations */
    /* ---------------------------------------------------------------------- */

    /* initialize variables for feasibility testing */
    maxax = NAPZERO ;   /* stores hi range of possible values for a'x */
    minax = NAPZERO ;   /* stores lo range of possible values for a'x */

    domhi = NAPINF ;    /* upper bound on domain where dual max achieved */
    domlo = -NAPINF ;   /* lower bound on domain where dual max achieved */

    /* initialize other variables */
    slope = NAPZERO ;   /* slope of dual func ignoring break points at lambda */
    slope0 = NAPZERO ;  /* slope of the dual function at lambda = 0 */
    b = NAPZERO ;       /* adjustments to right side due to fixed variables */
    lambdaL = +NAPINF ; /* most negative break point */
    lambdaR = -NAPINF ; /* most positive break point */
    dL = +NAPINF ;      /* value of slope at lambdaL */
    dR = -NAPINF ;      /* value of slope at lambdaR */
    num = NAPZERO ;     /* numerator of lambda estimate in variable fixing */
    den = NAPZERO ;     /* denominator of lambda estimate in variable fixing */
    nuf = 0 ;           /* number of unfixed variables */
    nkf = 0 ;           /* number of known free variables */
    nbound = 0 ;        /* no variables known to be at bounds */
    nfree = 0 ;         /* no variables known to be free */

    /* ====================================================================== */
    /* === solve the knapsack problem (3 cases: d > 0, d = 0, complement) === */
    /* ====================================================================== */

    /* lo and/or hi could have infinite valued components. */

    if ( d_is_pos )
    {
        /* ================================================================== */
        /* === case when (d > 0) ============================================ */
        /* ================================================================== */

        /* if no starting guess given, compute one by variable fixing */
        if ( !use_lambda )
        {
            if ( (use_prior_data == TRUE) && (akakdk < NAPINF) )
            {
                den = akakdk ;
                if ( d_is_one )
                {
                    num = nap_dot (y, a, n) ;
                }
                else
                {
                    num = nap_dot (y, ad, n) ;
                }
                if ( blo == bhi )
                {
                    b = blo ;
                }
                else /* blo != bhi */
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT u = (d_is_one) ? y [k] : y [k]/d [k] ;
                        if ( loExists && (u < lo [k]) )
                        {
                            slope0 += a [k]*lo [k] ;
                        }
                        else if ( hiExists && (u > hi [k]) )
                        {
                            slope0 += a [k]*hi [k] ;
                        }
                        else
                        {
                            slope0 += a [k]*u ;
                        }
                    }
                    /* determine bracketting interval and b */
                    BRACKET ;
                }
            }
            else /* starting from scratch */
            {
                if ( blo == bhi )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            den += ak*ak ;
                            num +=  y [k]*ak ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT s = ak/d [k] ;
                            ad [k] = s ;
                            den += ak*s ;
                            num +=  y [k]*s ;
                        }
                    }
                    b = blo ;
                    if ( Parm->return_data )
                    {
                        napdata->akakdk = den ;
                    }
                }
                else /* blo != bhi */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            den += ak*ak ;
                            num +=  y [k]*ak ;
                            const NAPFLOAT u = y [k] ;
                            if ( loExists && (u < lo [k]) )
                            {
                                slope0 += ak*lo [k] ;
                            }
                            else if ( hiExists && (u > hi [k]) )
                            {
                                slope0 += ak*hi [k] ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT s = ak/d [k] ;
                            ad [k] = s ;
                            den += ak*s ;
                            num +=  y [k]*s ;
                            const NAPFLOAT u = y [k]/d [k] ;
                            if ( loExists && (u < lo [k]) )
                            {
                                slope0 += ak*lo [k] ;
                            }
                            else if ( hiExists && (u > hi [k]) )
                            {
                                slope0 += ak*hi [k] ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }
                    if ( Parm->return_data )
                    {
                        napdata->akakdk = den ;
                    }
                    /* determine bracketting interval and b */
                    BRACKET ;
                }
            }
            if ( den == NAPZERO )
            {
                /* when den = 0, a = 0 */
                if ( (blo > NAPZERO) || (bhi < NAPZERO) )
                {
                    status = NAPHEAP_STATUS_INFEASIBLE ;
                    return (nap_wrapup (status, napdata, NAPZERO)) ;
                }
                /* otherwise, the problem has no linear constraint */
                for (k = 0; k < n; k++)
                {
                    NAPFLOAT t ;
                    const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                    const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
                    t = (d_is_one) ? y [k] : y [k]/d [k] ;
                    if ( t < lok )
                    {
                        t = lok ;
                    }
                    else if ( t > hik )
                    {
                        t = hik ;
                    }
                    x [k] = t ;
                }
                if ( Parm->return_data )
                {
                    napdata->akakdk = NAPZERO ;
                }
                return (nap_wrapup (NAPHEAP_STATUS_OK, napdata, NAPZERO)) ;
            }
            lambda = (num - b)/den ;
            numFV = num ; /* numerator for variable fixing */
            denFV = den ; /* denominator for variable fixing */

            /* compute slope at starting point, slope at lambda = 0,
               and den for Newton */
            den = NAPZERO ;
            if ( blo == bhi )
            {
                if ( d_is_one )
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT ak = a [k] ;
                        const NAPFLOAT u = y [k] ;
                        const NAPFLOAT t = u - lambda*ak ;
                        const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                        const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
                        if ( t < lok)
                        {
                            x [k] = lok ;
                            slope += ak*lok ;
                        }
                        else if ( t > hik )
                        {
                            x [k] = hik ;
                            slope += ak*hik ;
                        }
                        else
                        {
                            x [k] = t ;
                            slope += ak*t ;
                            den += ak*ak ;
                        }
                        if ( u < lok )
                        {
                            slope0 += ak*lok ;
                        }
                        else if ( u > hik )
                        {
                            slope0 += ak*hik ;
                        }
                        else
                        {
                            slope0 += ak*u ;
                        }
                    }
                }
                else /* d not one */
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT ak = a [k] ;
                        const NAPFLOAT u = y [k]/d [k] ;
                        const NAPFLOAT adk = ad [k] ;
                        const NAPFLOAT t = u - lambda*adk ;
                        const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                        const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
                        if ( t < lok)
                        {
                            x [k] = lok ;
                            slope += ak*lok ;
                        }
                        else if ( t > hik )
                        {
                            x [k] = hik ;
                            slope += ak*hik ;
                        }
                        else
                        {
                            x [k] = t ;
                            slope += ak*t ;
                            den += ak*adk ;
                        }
                        if ( u < lok )
                        {
                            slope0 += ak*lok ;
                        }
                        else if ( u > hik )
                        {
                            slope0 += ak*hik ;
                        }
                        else
                        {
                            slope0 += ak*u ;
                        }
                    }
                }
                /* determine bracketting interval */
                BRACKET ;
            }
            else /* blo != bhi (slope0 already computed) */
            {
                if ( d_is_one )
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT ak = a [k] ;
                        const NAPFLOAT t = y [k] - lambda*ak ;
                        const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                        if ( t < lok )
                        {
                            x [k] = lok ;
                            slope += ak*lok ;
                        }
                        else
                        {
                            if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope +=ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ak ;
                            }
                        }
                    }
                }
                else
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT ak = a [k] ;
                        const NAPFLOAT t = (y [k] - lambda*ak)/d [k] ;
                        const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                        if ( t < lok )
                        {
                            x [k] = lok ;
                            slope += ak*lok ;
                        }
                        else
                        {
                            if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope +=ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ad [k] ;
                            }
                        }
                    }
                }
            }
        }
        else /* use lambda, compute slope at starting guess and at lambda = 0*/
        {
            if ( use_prior_data == TRUE )
            {
                /* no need to compute slope at lambda = 0 when blo = bhi */
                if ( blo == bhi )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT t = y [k] - lambda*ak ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope += ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ak ;
                            }
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT t = (y [k] - lambda*ak)/d [k] ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope += ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ad [k] ;
                            }
                        }
                    }
                    b = blo ;
                    lambdaL =-NAPINF ;
                    lambdaR = NAPINF ;
                    dL = NAPINF ;
                    dR =-NAPINF ;
                }
                else /* blo < bhi, also compute slope at lambda = 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT u = y [k] ;
                            const NAPFLOAT t = u - lambda*ak ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( t > hik )
                            {
                                x [k] = hik ;
                                slope += ak*hik ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ak ;
                            }
                            if ( u < lok )
                            {
                                slope0 += ak*lok ;
                            }
                            else if ( u > hik )
                            {
                                slope0 += ak*hik ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT s = ad [k] ;
                            const NAPFLOAT u = y [k]/d [k] ;
                            const NAPFLOAT t = u - lambda*s ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            const NAPFLOAT hik = (hiExists) ? hi [k] :  NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( t > hik )
                            {
                                x [k] = hik ;
                                slope += ak*hik ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*s ;
                            }
                            if ( u < lok )
                            {
                                slope0 += ak*lok ;
                            }
                            else if ( u > hik )
                            {
                                slope0 += ak*hik ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }
                    /* determine bracketting interval */
                    BRACKET ;
                }
            }
            else /* use_prior_data is FALSE */
            {
                /* no need to compute slope at lambda = 0 when blo = bhi */
                if ( blo == bhi )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            const NAPFLOAT t = y [k] - lambda*ak ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( t > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT s = ak/d [k] ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            ad [k] = s ;
                            const NAPFLOAT t = (y [k]/d [k]) - lambda*s ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( t > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                        }
                    }
                    b = blo ;
                    lambdaL =-NAPINF ;
                    lambdaR = NAPINF ;
                    dL = NAPINF ;
                    dR =-NAPINF ;
                }
                else /* blo < bhi, also compute slope at lambda = 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT u = y [k] ;
                            const NAPFLOAT t = u - lambda*ak ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope += ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*ak ;
                            }
                            if ( u < lok )
                            {
                                slope0 += ak*lok ;
                            }
                            else if ( hiExists && (u > hi [k]) )
                            {
                                slope0 += ak*hi [k] ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }    
                    else 
                    {    
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT s = ak/d [k] ;
                            ad [k] = s ;
                            const NAPFLOAT u = y [k]/d [k] ;
                            const NAPFLOAT t = u - lambda*s ;
                            const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                            if ( t < lok)
                            {
                                x [k] = lok ;
                                slope += ak*lok ;
                            }
                            else if ( hiExists && (t > hi [k]) )
                            {
                                x [k] = hi [k] ;
                                slope += ak*hi [k] ;
                            }
                            else
                            {
                                x [k] = t ;
                                slope += ak*t ;
                                den += ak*s ;
                            }
                            if ( u < lok )
                            {
                                slope0 += ak*lok ;
                            }
                            else if ( hiExists && (u > hi [k]) )
                            {
                                slope0 += ak*hi [k] ;
                            }
                            else
                            {
                                slope0 += ak*u ;
                            }
                        }
                    }
                    /* determine bracketting interval */
                    BRACKET ;
                }
            }
        }
        slope -= b ;

        /* update bracketting interval based on slope at starting guess */
        if ( slope > NAPZERO )
        {
            if ( dL < slope )
            {
                lambda = lambdaL ;
                slope = dL ;
            }
            else
            {
                lambdaL = lambda ;
                dL = slope ;
            }
        }
        else if ( slope < NAPZERO )
        {
            if ( dR > slope )
            {
                lambda = lambdaR ;
                slope = dR ;
            }
            else
            {
                lambdaR = lambda ;
                dR = slope ;
            }
        }
        else /* given lambda is optimal */
        {
            status = NAPHEAP_STATUS_OK ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        /* At this point, we have a starting guess that was either given
           or was computed by a variable fixing iteration. x has been
           set in accordance with the bounds at the starting guess.
           The slope is known at both the starting guess and at lambda = 0
           (unless blo = bhi and use_lambda = TRUE), and we have an
           interval that brackets the root. We now fix bound variables,
           remove components of the a array that vanish, initialize the
           uf array of unfixed indices, and compute either a Newton or
           a variable fixing iteration. */

        if ( K == 0 )
        {
            /* x values are set according to the starting guess. If
               lambda = 0 is the current iterate, then recompute x using
               lambda = 0 */
            if ( lambda == NAPZERO )
            {
                for (k = 0; k < n; k++)
                {
                    const NAPFLOAT t = (d_is_one) ? y [k] : y [k]/d [k] ;
                    if ( loExists && (t < lo [k]) )
                    {
                        x [k] = lo [k] ;
                    }
                    else if ( hiExists && (t > hi [k]) )
                    {
                        x [k] = hi [k] ;
                    }
                    else
                    {
                        x [k] = t ;
                    }
                    if ( a [k] == NAPZERO )
                    {
                        continue ;
                    }
                    else
                    {
                        ay [k] = y [k]/a [k] ;
                    }
                    uf [nuf] = k ;
                    nuf++ ;
                }
            }
            else /* lambda != 0 */
            {
                for (k = 0; k < n; k++)
                {
                    if ( a [k] == NAPZERO )
                    {
                        const NAPFLOAT t = (d_is_one) ? y [k] : y [k]/d [k] ;
                        if ( loExists && (t < lo [k]) )
                        {
                            x [k] = lo [k] ;
                        }
                        else if ( hiExists && (t > hi [k]) )
                        {
                            x [k] = hi [k] ;
                        }
                        else
                        {
                            x [k] = t ;
                        }
                        continue ;
                    }
                    ay [k] = y [k]/a [k] ;
                    uf [nuf] = k ;
                    nuf++ ;
                }
            }
            status = napsearch (x, &lambda, lambdaL, lambdaR, b, slope,
                                ay, ad, a, lo, hi, n, breakpts, breaknext,
                                nuf, &nkf, &nfree, &nbound, uf, kf,
                                free_heap, bound_heap, Stat, Parm,
                                loExists, hiExists) ;

            if ( status == NAPHEAP_STATUS_OK )
            {
                napsolution1 (x, y, d, a, lo, hi, lambda, slope, kf, nkf,
                              free_heap, bound_heap, nfree, nbound, d_is_one) ;
            }

            ASSERT (status == NAPHEAP_STATUS_OK) ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        use_newton = FALSE ;
        prevlambda = lambda ;
        prevslope = slope ;
        if ( newton )
        {
            if ( den != NAPZERO ) /* note: lambda=0 => using den of prevlambda*/
            {
                lambda += Parm->newton_scale*slope/den ; /* scaled Newton */
                if ( (lambda >= lambdaL) && (lambda <= lambdaR) )
                {
                    use_newton = TRUE ;
                }
            }

            /* try secant if newton failed */
            if ( !use_newton )
            {
                if ( (lambdaL > -NAPINF) && (lambdaR < NAPINF) ) /* use secant*/
                {
                    /* express the secant update relative to the side with
                       slope of smallest magnitude */
                    if ( dL < -dR )
                    {
                        lambda = lambdaL - dL*(lambdaL - lambdaR)/(dL-dR) ;
                    }
                    else
                    {
                        lambda = lambdaR - dR*(lambdaL - lambdaR)/(dL-dR) ;
                    }
                    use_newton = TRUE ;
                }
            }
        }

        int zero_bracket = FALSE ;
        if ( (lambdaL == NAPZERO) || (lambdaR == NAPZERO) )
        {
            zero_bracket = TRUE ; /* one side of bracketing interval is 0 */
        }

        /* fix variables and evaluate next iterate */
        slope = NAPZERO ;
        if ( use_newton )
        {
            den = NAPZERO ;
            if ( !zero_bracket ) /* zero not in bracketting interval */
            {
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                const NAPFLOAT yk = y [k] ;
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        slope += ak*hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                const NAPFLOAT yk = y [k] ;
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            else /* ak = 0 */
                            {
                                const NAPFLOAT yk = y [k] ;
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                const NAPFLOAT s = ad [k] ;
                                const NAPFLOAT r = y [k]/ak ;
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        slope += ak*hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                const NAPFLOAT s = ad [k] ;
                                const NAPFLOAT r = y [k]/ak ;
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                            else /* ak = 0 */
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                const NAPFLOAT yk = y [k] ;
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                const NAPFLOAT yk = y [k] ;
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else if ( hiExists && (t > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                    slope += ak*hi [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            else /* ak == 0 */
                            {
                                const NAPFLOAT yk = y [k] ;
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        if ( d_is_one )
                        {
                            for (k = 0; k < n; k++)
                            {
                                const NAPFLOAT ak = a [k] ;
                                if ( ak > NAPZERO )
                                {
                                    const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                    if ( x [k] == hik )
                                    {
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    const NAPFLOAT yk = y [k] ;
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else if ( loExists && (t < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        slope += ak*lo [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                                else if ( ak < NAPZERO )
                                {
                                    const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                    if ( x [k] == lok )
                                    {
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    const NAPFLOAT yk = y [k] ;
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( hiExists && (t > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        slope += ak*hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                                else /* ak == 0 */
                                {
                                    const NAPFLOAT yk = y [k] ;
                                    if ( loExists && (yk < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                    }
                                    else if ( hiExists && (yk > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = yk ;
                                    }
                                    continue ;
                                }
                                uf [nuf] = k ;
                                nuf++ ;
                            }
                        }
                        else
                        {
                            for (k = 0; k < n; k++)
                            {
                                const NAPFLOAT ak = a [k] ;
                                if ( ak > NAPZERO )
                                {
                                    const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                    if ( x [k] == hik )
                                    {
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else if ( loExists && (t < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        slope += ak*lo [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                                else if ( ak < NAPZERO )
                                {
                                    const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                    if ( x [k] == lok )
                                    {
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( hiExists && (t > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        slope += ak*hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                                else /* ak == 0 */
                                {
                                    const NAPFLOAT xk = y [k]/d [k] ;
                                    if ( loExists && (xk < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                    }
                                    else if ( hiExists && (xk > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                    }
                                    else
                                    {
                                        x [k] = xk ;
                                    }
                                    continue ;
                                }
                                uf [nuf] = k ;
                                nuf++ ;
                            }
                        }
                    }
                }
            }
            else if ( prevlambda == NAPZERO ) /*bracket is [0, INF)|(-INF, 0]*/
            {
                /* fix variables at lambda = 0 */
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( yk <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    continue ;
                                }
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else if ( hiExists && (t > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                    slope += ak*hi [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( yk >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    continue ;
                                }
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            const NAPFLOAT s = ad [k] ;
                            const NAPFLOAT r = y [k]/ak ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( r*s <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    continue ;
                                }
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else if ( hiExists && (t > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                    slope += ak*hi [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( r*s >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    continue ;
                                }
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( yk >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    continue ;
                                }
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( yk <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    continue ;
                                }
                                ay [k] = yk/ak ;
                                const NAPFLOAT t = yk - lambda*ak ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else if ( hiExists && (t > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                    slope += ak*hi [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*ak ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            const NAPFLOAT s = ad [k] ;
                            const NAPFLOAT r = y [k]/ak ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( r*s >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    continue ;
                                }
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  > hik )
                                {
                                    x [k] = hik ;
                                    slope += ak*hik ;
                                }
                                else if ( loExists && (t < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                    slope += ak*lo [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( r*s <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    continue ;
                                }
                                ay [k] = r ;
                                const NAPFLOAT t = (r - lambda)*s ;
                                if ( t  < lok )
                                {
                                    x [k] = lok ;
                                    slope += ak*lok ;
                                }
                                else if ( hiExists && (t > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                    slope += ak*hi [k] ;
                                }
                                else
                                {
                                    x [k] = t ;
                                    slope += ak*t ;
                                    den += ak*s ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
            }
            else /* bracket is [0, lambda] or [lambda, 0] */
            {
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                    if ( yk > hik )
                                    {
                                        x [k] = hik ;
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                            }
                            else /* aj < 0 */
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                    if ( yk < lok )
                                    {
                                        x [k] = lok ;
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    const NAPFLOAT hik =
                                                     (hiExists) ? hi [k]:NAPINF;
                                    if ( r*s > hik )
                                    {
                                        x [k] = hik ;
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                            }
                            else /* aj < 0 */
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    const NAPFLOAT lok =
                                                     (loExists) ?lo [k]:-NAPINF;
                                    if ( r*s < lok )
                                    {
                                        x [k] = lok ;
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                    if ( yk < lok )
                                    {
                                        x [k] = lok ;
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak;
                                    }
                                }
                            }
                            else /* aj < 0 */
                            {
                                const NAPFLOAT lok =
                                                 (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                    if ( yk > hik )
                                    {
                                        x [k] = hik ;
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    ay [k] = yk/ak ;
                                    const NAPFLOAT t = yk - lambda*ak ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*ak ;
                                    }
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik =
                                                  (hiExists) ? hi [k] : NAPINF ;
                                if ( x [k] == hik )
                                {
                                    b -= ak*hik ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT lok =
                                                     (loExists) ?lo [k]:-NAPINF;
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( r*s < lok )
                                    {
                                        x [k] = lok ;
                                        b -= ak*lok ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                            }
                            else /* aj < 0 */
                            {
                                const NAPFLOAT lok = (loExists) ? lo [k] : -NAPINF ;
                                if ( x [k] == lok )
                                {
                                    b -= ak*lok ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( r*s > hik )
                                    {
                                        x [k] = hik ;
                                        b -= ak*hik ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                    const NAPFLOAT t = (r - lambda)*s ;
                                    if ( t  < lok )
                                    {
                                        x [k] = lok ;
                                        slope += ak*lok ;
                                    }
                                    else if ( t > hik )
                                    {
                                        x [k] = hik ;
                                        slope += ak*hik ;
                                    }
                                    else
                                    {
                                        x [k] = t ;
                                        slope += ak*t ;
                                        den += ak*s ;
                                    }
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
            }
            /* If nuf = 0, then all the variables are fixed. Either the
               problem is infeasible or the optimal solution has been found. */
            if ( nuf == 0 )
            {
                /* check for feasibility */
                NAPFLOAT t = NAPZERO ;
                for (k = 0; k < n; k++)
                {
                    t += a [k]*x [k] ;
                }
                if ( (t >= blo) && (t <= bhi) ) /* feasible and optimal */
                {
                    status = NAPHEAP_STATUS_OK ;
                    lambda = NAPZERO ;
                }
                else                            /* infeasible */
                {
                    status = NAPHEAP_STATUS_INFEASIBLE ;
                }
                return (nap_wrapup (status, napdata, lambda)) ;
            }
            slope -= b ;
        }
        else /* variable fixing iterate */
        {
            /* need to compute num and dem if use_lambda is TRUE */
            if ( use_lambda )
            {
                den = NAPZERO ;
                num = NAPZERO ;
                if ( d_is_one )
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT ak = a [k] ;
                        den += ak*ak ;
                        num += y [k]*ak ;
                    }
                }
                else
                {
                    for (k = 0; k < n; k++)
                    {
                        const NAPFLOAT s = ad [k] ;
                        den += a [k]*s ;
                        num += y [k]*s ;
                    }
                }
            }
            else /* num and den already computed above */
            {
                num = numFV ;
                den = denFV ;
            }
            /* this differs from Newton both in the formula for num and den
               and due to the fact that there is no lambda in the bracketting
               interval */
            if ( !zero_bracket ) /* zero not in bracketting interval */
            {
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else /* ak = 0 */
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            ay [k] = yk/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else /* ak = 0 */
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            ay [k] = y [k]/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else /* ak == 0 */
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            ay [k] = yk/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak > NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else if ( ak < NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else /* ak == 0 */
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            ay [k] = y [k]/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
            }
            else if ( prevlambda == NAPZERO ) /*bracket is [0, INF) |(-INF, 0]*/
            {
                /* fix variables at lambda = 0 */
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok = (loExists)? lo [k]:-NAPINF;
                                if ( yk <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( yk >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            ay [k] = yk/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            const NAPFLOAT s = ad [k] ;
                            const NAPFLOAT r = y [k]/ak ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT lok = (loExists) ?lo [k]:-NAPINF;
                                if ( r*s <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( r*s >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            ay [k] = r ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT yk = y [k] ;
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( yk >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT lok = (loExists) ?lo [k]:-NAPINF;
                                if ( yk <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                            }
                            ay [k] = yk/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            const NAPFLOAT s = ad [k] ;
                            const NAPFLOAT r = y [k]/ak ;
                            if ( ak > NAPZERO )
                            {
                                const NAPFLOAT hik = (hiExists) ? hi [k]:NAPINF;
                                if ( r*s >= hik )
                                {
                                    b -= ak*hik ;
                                    x [k] = hik ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            else /* ak < 0 */
                            {
                                const NAPFLOAT lok = (loExists) ?lo [k]:-NAPINF;
                                if ( r*s <= lok )
                                {
                                    b -= ak*lok ;
                                    x [k] = lok ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                            }
                            ay [k] = r ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
            }
            else /* bracket is [0, lambda] or [lambda, 0] */
            {
                if ( prevslope > NAPZERO )
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            const NAPFLOAT yk = y [k] ;
                            if ( ak == NAPZERO )
                            {
                                if ( loExists && (yk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (yk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = yk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    if ( hiExists && (yk > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        b -= ak*hi [k] ;
                                        den -= ak*ak ;
                                        num -= yk*ak ;
                                        continue ;
                                    }
                                }
                            }
                            else /* aj < 0 */
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    den -= ak*ak ;
                                    num -= yk*ak ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    if ( loExists && (yk < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        b -= ak*lo [k] ;
                                        den -= ak*ak ;
                                        num -= yk*ak ;
                                        continue ;
                                    }
                                }
                            }
                            ay [k] = yk/ak ;
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( hiExists && (r*s > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        b -= ak*hi [k] ;
                                        den -= ak*s ;
                                        num -= y [k]*s ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            else /* aj < 0 */
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( loExists && (r*s < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        b -= ak*lo [k] ;
                                        den -= ak*s ;
                                        num -= y [k]*s ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
                else /* prevslope < 0 */
                {
                    if ( d_is_one )
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    den -= ak*ak ;
                                    num -= y [k]*ak ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( loExists && (r*ak < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        b -= ak*lo [k] ;
                                        den -= ak*ak ;
                                        num -= y [k]*ak ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            else /* aj < 0 */
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    den -= ak*ak ;
                                    num -= y [k]*ak ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( hiExists && (r*ak > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        b -= ak*hi [k] ;
                                        den -= ak*ak ;
                                        num -= y [k]*ak ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                    else
                    {
                        for (k = 0; k < n; k++)
                        {
                            const NAPFLOAT ak = a [k] ;
                            if ( ak == NAPZERO )
                            {
                                const NAPFLOAT xk = y [k]/d [k] ;
                                if ( loExists && (xk < lo [k]) )
                                {
                                    x [k] = lo [k] ;
                                }
                                else if ( hiExists && (xk > hi [k]) )
                                {
                                    x [k] = hi [k] ;
                                }
                                else
                                {
                                    x [k] = xk ;
                                }
                                continue ;
                            }
                            else if ( ak > NAPZERO )
                            {
                                if ( hiExists && (x [k] == hi [k]) )
                                {
                                    b -= ak*hi [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( loExists && (r*s < lo [k]) )
                                    {
                                        x [k] = lo [k] ;
                                        b -= ak*lo [k] ;
                                        den -= ak*s ;
                                        num -= y [k]*s ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            else /* aj < 0 */
                            {
                                if ( loExists && (x [k] == lo [k]) )
                                {
                                    b -= ak*lo [k] ;
                                    const NAPFLOAT s = ad [k] ;
                                    den -= ak*s ;
                                    num -= y [k]*s ;
                                    continue ;
                                }
                                else /* ak > 0 and slope0 < 0 */
                                {
                                    const NAPFLOAT s = ad [k] ;
                                    const NAPFLOAT r = y [k]/ak ;
                                    if ( hiExists && (r*s > hi [k]) )
                                    {
                                        x [k] = hi [k] ;
                                        b -= ak*hi [k] ;
                                        den -= ak*s ;
                                        num -= y [k]*s ;
                                        continue ;
                                    }
                                    ay [k] = r ;
                                }
                            }
                            uf [nuf] = k ;
                            nuf++ ;
                        }
                    }
                }
            }
            /* If nuf = 0, then all the variables are fixed. Either the
               problem is infeasible or the optimal solution has been found. */
            if ( nuf == 0 )
            {
                /* check for feasibility */
                NAPFLOAT t = NAPZERO ;
                for (k = 0; k < n; k++)
                {
                    t += a [k]*x [k] ;
                }
                if ( (t >= blo) && (t <= bhi) ) /* feasible and optimal */
                {
                    status = NAPHEAP_STATUS_OK ;
                    lambda = NAPZERO ;
                }
                else                            /* infeasible */
                {
                    status = NAPHEAP_STATUS_INFEASIBLE ;
                }
                return (nap_wrapup (status, napdata, lambda)) ;
            }
            if ( newton )
            {
                lambda = (num - b)/den ;
                den = NAPZERO ;
                if ( d_is_one )
                {
                    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                        const NAPFLOAT aj = a [j] ;
                        const NAPFLOAT t = y [j] - lambda*aj ;
                        if ( loExists && (t < lo [j]) )
                        {
                            x [j] = lo [j] ;
                            slope += aj*lo [j] ;
                        }
                        else if ( hiExists && (t > hi [j]) )
                        {
                            x [j] = hi [j] ;
                            slope += aj*hi [j] ;
                        }
                        else
                        {
                            x [j] = t ;
                            slope += aj*t ;
                            den += aj*aj ;
                        }
                    END_LOOP ;
                }
                else
                {
                    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                        const NAPFLOAT aj = a [j] ;
                        const NAPFLOAT t = (ay [j] - lambda)*ad [j] ;
                        if ( loExists && (t < lo [j]) )
                        {
                            x [j] = lo [j] ;
                            slope += aj*lo [j] ;
                        }
                        else if ( hiExists && (t > hi [j]) )
                        {
                            x [j] = hi [j] ;
                            slope += aj*hi [j] ;
                        }
                        else
                        {
                            x [j] = t ;
                            slope += aj*t ;
                            den += aj*ad [j] ;
                        }
                    END_LOOP ;
                }
                slope -= b ;
            }
        }

        /* ================================================================== */
        /* Begin newton algorithm */
        /* ================================================================== */
        if ( newton )
        {
            /* update bracketting interval based on slope at current iterate */
            if ( slope > NAPZERO )
            {
                lambdaL = lambda ;
                dL = slope ;
            }
            else if ( slope < NAPZERO )
            {
                lambdaR = lambda ;
                dR = slope ;
            }
            else /* given lambda is optimal */
            {
                status = NAPHEAP_STATUS_OK ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }

            /* We now have an iterate lambda, the slope and den at lambda,
               the array uf of unfixed indices */

            /* ============================================================== */
            /* Start Newton method */
            /* ============================================================== */
            /* Perform up to K iterations of Newton's method. If we cannot
               perform a Newton step since L'' vanishes, then perform a
               secant step as long as both sides of the bracketing interval
               are finite. If one side is infinite, then perform a variable
               fixing iteration. Switch to the breakpoint algorithm if
               no variables are fixed in an iteration, the iteration limit K
               is reached, or either a Newton or a secant iteration is
               performed which generates a point on the opposite side of
               the root. If a variable fixing step takes us to the other
               side of the root, then we try to perform one additional Newton
               iteration before switching to the breakpoint algorithm.
               When the Newton iteration fails to fix a variable,
               then we switch to the break point algorithm. */
            status = NAPHEAP_STATUS_KEEP_LOOKING ; /* default status */

            /* number of steps */
            nnewton    = 0 ;
            nsecant    = 0 ;
            nvarfix    = 0 ;
            prevstep = NONE ;

            /* When lambda crosses root, start_napsearch becomes true. */
            start_napsearch = FALSE ;

            /* If a variable fixing iteration crosses the root, then
               start_napsearch_next becomes TRUE */
            start_napsearch_next = FALSE ;

            for ( it = 1; it <= K; it++ )
            {
                crossed = FALSE ; /* changes to TRUE when root is crossed */
                if ( prevslope*slope < NAPZERO )
                {
                    crossed = TRUE ;
                }

                /* ========================================================== */
                /* Check to see if we should switch to napsearch */
                /* ========================================================== */
                if ( start_napsearch_next || (it == K) )
                {
                    start_napsearch = TRUE;
                }
                else if ( (it > 1) ||
                          (use_lambda && (fabs (slope) <= fabs (prevslope))) )
                {
                    if ( crossed && (prevstep != VARFIX) )
                    {
                        start_napsearch = TRUE;
                    }
                    else if ( crossed ) /* start napsearch next iteration */
                    {
                        start_napsearch_next = TRUE;
                    }
                }
                pprevslope = prevslope ;
                prevslope = slope;    /* save current slope */
                pprevlambda = prevlambda ;
                prevlambda = lambda ; /* save current lambda */

                /* ========================================================== */
                /* Step computation */
                /* ========================================================== */
                /* If L'' = 0, use secant if both sides of the bracketing
                   interval are finite otherwise use variable fixing. */
                if ( den == NAPZERO )
                {
                    /* Take a variable fixing step if bracket interval inf.
                       This will generate a point inside [lambdaL, lambdaR]
                       since we also fix variables. */
                    if ( lambdaL == -NAPINF || lambdaR == NAPINF )
                    {
                        prevstep = VARFIX ;
                        nvarfix++ ;
                        den = NAPZERO ;
                        num = NAPZERO ;
                        if ( d_is_one )
                        {
                            if ( slope > NAPZERO )
                            {
                                LOOP_OVER_UNFIXED ;
                                {
                                    const NAPFLOAT aj = a [j] ;
                                    if ( aj > NAPZERO )
                                    {
                                        if ( loExists && (x [j] == lo [j]) )
                                        {
                                            b -= aj*lo [j] ;
                                            continue ;
                                        }
                                    }
                                    else /* aj < 0 */
                                    {
                                        if ( hiExists && (x [j] == hi [j]) )
                                        {
                                            b -= aj*hi [j] ;
                                            continue ;
                                        }
                                    }
                                    den += aj*aj ;
                                    num += aj*y [j] ;
                                }
                                END_UNFIXED_LOOP ;
                            }
                            else /* slope < 0 */
                            {
                                LOOP_OVER_UNFIXED ;
                                {
                                    const NAPFLOAT aj = a [j] ;
                                    if ( aj > NAPZERO )
                                    {
                                        if ( hiExists && (x [j] == hi [j]) )
                                        {
                                            b -= aj*hi [j] ;
                                            continue;
                                        }
                                    }
                                    else /* aj < 0 */
                                    {
                                        if ( loExists && (x [j] == lo [j]) )
                                        {
                                            b -= aj*lo [j] ;
                                            continue ;
                                        }
                                    }
                                    den += aj*aj ;
                                    num += aj*y [j] ;
                                }
                                END_UNFIXED_LOOP ;
                            }
                        }
                        else
                        {
                            if ( slope > NAPZERO )
                            {
                                LOOP_OVER_UNFIXED ;
                                {
                                    const NAPFLOAT aj = a [j] ;
                                    if ( aj > NAPZERO )
                                    {
                                        if ( loExists && (x [j] == lo [j]) )
                                        {
                                            b -= aj*lo [j] ;
                                            continue ;
                                        }
                                    }
                                    else /* aj < 0 */
                                    {
                                        if ( hiExists && (x [j] == hi [j]) )
                                        {
                                            b -= aj*hi [j] ;
                                            continue ;
                                        }
                                    }
                                    const NAPFLOAT t = aj*ad [j] ;
                                    den += t ;
                                    num += t*ay [j] ;
                                }
                                END_UNFIXED_LOOP ;
                            }
                            else /* slope < 0 */
                            {
                                LOOP_OVER_UNFIXED ;
                                {
                                    const NAPFLOAT aj = a [j] ;
                                    if ( aj > NAPZERO )
                                    {
                                        if ( hiExists && (x [j] == hi [j]) )
                                        {
                                            b -= aj*hi [j] ;
                                            continue;
                                        }
                                    }
                                    else /* aj < 0 */
                                    {
                                        if ( loExists && (x [j] == lo [j]) )
                                        {
                                            b -= aj*lo [j] ;
                                            continue ;
                                        }
                                    }
                                    const NAPFLOAT t = aj*ad [j] ;
                                    den += t ;
                                    num += t*ay [j] ;
                                }
                                END_UNFIXED_LOOP ;
                            }
                        }

                        if ( nuf == 0 )
                        {
                            /* all components fixed, but slope != 0 */
                            status = NAPHEAP_STATUS_INFEASIBLE ;
                            return (nap_wrapup (status, napdata, lambda)) ;
                        }
                        /* den != 0 since k > -1 */
                        lambda = (num - b)/den ;
                    }
                    else /* den = 0 and finite interval, perform secant step */
                    {
                        if ( prevstep == SECANT1 )
                        {
                            prevstep = SECANT2 ;
                        }
                        else
                        {
                            prevstep = SECANT1 ;
                        }
                    }
                }
                else /*den != 0*/
                {
                    lambda += Parm->newton_scale*slope/den; /* scaled Newton */
                    if ( (lambda <= lambdaR) && (lambda >= lambdaL) )
                    {
                        prevstep = NEWTON ;
                        nnewton++;
                    }
                    else
                    {
                        if ( prevstep == SECANT1 )
                        {
                            prevstep = SECANT2 ;
                        }
                        else
                        {
                            prevstep = SECANT1 ;
                        }
                    }

                }

                /* Use secant step if lambda lands outside (lambdaL, lambdaR)
                   or den = 0.  This can only happen when lambda is
                   generated by a Newton iteration and the interval is finite.
                   We use two different secant steps. The first is based on
                   the function values and slopes at the ends of the bracketting
                   interval. The second is based on the last two iterates.
                   We alternate between these two ways to compute the secant
                   step. */
                if ( prevstep == SECANT2 )
                {
                    nsecant++ ;

                    /* express the secant update relative to the side with
                       slope of smallest magnitude */
                    const NAPFLOAT t = prevslope - pprevslope ;
                    if ( t != NAPZERO )
                    {
                        if ( fabs (prevslope) < fabs (pprevslope) )
                        {
                            lambda = prevlambda - prevslope*
                                 (prevlambda - pprevlambda)/t ;
                        }
                        else
                        {
                            lambda = pprevlambda - pprevslope*
                                 (prevlambda - pprevlambda)/t ;
                        }
                    }
                    /* if the step was no good, then switch to a secant step
                       based on the bracketting interval */
                    if ((t == NAPZERO)||(lambda < lambdaL)||(lambda > lambdaR))
                    {
                        nsecant-- ;
                        prevstep = SECANT1 ;
                    }
                }
                if ( prevstep == SECANT1 )
                {
                    nsecant++ ;

                    /* express the secant update relative to the side with
                       slope of smallest magnitude */
                    if ( dL < -dR )
                    {
                        lambda = lambdaL - dL*(lambdaL - lambdaR)/(dL-dR) ;
                    }
                    else
                    {
                        lambda = lambdaR - dR*(lambdaL - lambdaR)/(dL-dR) ;
                    }
                }
                /* lambda has now been determined (either by Newton, secant,
                   or variable fixing) */

                /* ========================================================== */
                /* Fix variables using previous lambda and slope              */
                /* evaluate L' and L'' at the new lambda                      */
                /* ========================================================== */

                slope = NAPZERO ;
                den   = NAPZERO ;
                /* If the previous step was a variable fixing iteration,
                   then we skip the fixing of variables since this was done
                   while the iterate was computed. */
                if ( prevstep == VARFIX )
                {
                    if ( start_napsearch )
                    {
                        if ( d_is_one )
                        {
                            /* fixing done already, compute slope, set x */
                            LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                                const NAPFLOAT aj = a [j] ;
                                const NAPFLOAT t = y [j] - lambda*aj ;
                                if ( loExists && (t < lo [j]) )
                                {
                                    x [j] = lo [j] ;
                                    slope += aj*lo [j] ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [j]) )
                                    {
                                        x [j] = hi [j] ;
                                        slope += aj*hi [j] ;
                                    }
                                    else
                                    {
                                        x [j] = t ;
                                        slope += aj*t ;
                                    }
                                }
                            END_LOOP ;
                        }
                        else
                        {
                            /* fixing done already, compute slope, set x */
                            LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                                const NAPFLOAT aj = a [j] ;
                                const NAPFLOAT t = (ay [j] - lambda)*ad [j] ;
                                if ( loExists && (t < lo [j]) )
                                {
                                    x [j] = lo [j] ;
                                    slope += aj*lo [j] ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [j]) )
                                    {
                                        x [j] = hi [j] ;
                                        slope += aj*hi [j] ;
                                    }
                                    else
                                    {
                                        x [j] = t ;
                                        slope += aj*t ;
                                    }
                                }
                            END_LOOP ;
                        }
                    }
                    else  /* start_napsearch = FALSE, prevstep = VARFIX, compute
                             slope & den for Newton step, fixing done earlier */
                    {
                        if ( d_is_one )
                        {
                            LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                                const NAPFLOAT aj = a [j] ;
                                const NAPFLOAT t = y [j] - lambda*aj ;
                                if ( loExists && (t < lo [j]) )
                                {
                                    x [j] = lo [j] ;
                                    slope += aj*lo [j] ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [j]) )
                                    {
                                        x [j] = hi [j] ;
                                        slope += aj*hi [j] ;
                                    }
                                    else
                                    {
                                        x [j] = t ;
                                        slope += aj*t ;
                                        den += aj*aj ;
                                    }
                                }
                            END_LOOP ;
                        }
                        else
                        {
                            LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                                const NAPFLOAT aj = a [j] ;
                                const NAPFLOAT t = (ay [j] - lambda)*ad [j] ;
                                if ( loExists && (t < lo [j]) )
                                {
                                    x [j] = lo [j] ;
                                    slope += aj*lo [j] ;
                                }
                                else
                                {
                                    if ( hiExists && (t > hi [j]) )
                                    {
                                        x [j] = hi [j] ;
                                        slope += aj*hi [j] ;
                                    }
                                    else
                                    {
                                        x [j] = t ;
                                        slope += aj*t ;
                                        den += aj*ad [j] ;
                                    }
                                }
                            END_LOOP ;
                        }
                    }
                }
                else if ( prevslope > NAPZERO )
                { /* previous step was Newton, optimal multiplier to right */
                    if ( start_napsearch )
                    { /* fix variables, no need to compute den */
                        LOOP_OVER_UNFIXED ;
                        {
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO )
                            {
                                FIX_LO ;
                                SLOPE_UPDATE_LO ;
                            }
                            else /* aj < 0 */
                            {
                                FIX_HI ;
                                SLOPE_UPDATE_HI ;
                            }
                        }
                        END_UNFIXED_LOOP ;
                    }
                    else /* start_napsearch = FALSE, slope > 0 */
                    { /* continue Newton iteration, fix variables, compute den*/
                        LOOP_OVER_UNFIXED ;
                        {
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO )
                            {
                                FIX_LO ;
                                SLOPE_UPDATE_LO_DEN ;
                            }
                            else /* aj < 0 */
                            {
                                FIX_HI ;
                                SLOPE_UPDATE_HI_DEN ;
                            }
                        }
                        END_UNFIXED_LOOP ;
                    }
                }
                else /* prevslope < 0 */
                { /* Newton step previously, optimal multiplier to the left */
                    if ( start_napsearch )
                    { /* fix variables and compute break points */
                        LOOP_OVER_UNFIXED ;
                        {
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO )
                            {
                                FIX_HI ;
                                SLOPE_UPDATE_HI ;
                            }
                            else /* aj < 0 */
                            {
                                FIX_LO ;
                                SLOPE_UPDATE_LO ;
                            }
                        }
                        END_UNFIXED_LOOP ;
                    }
                    else /* start_napsearch = FALSE, slope < 0 */
                    { /* continue Newton iteration, fix variables, compute den*/
                        LOOP_OVER_UNFIXED ;
                        {
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO )
                            {
                                FIX_HI ;
                                /* update slope and compute den*/
                                SLOPE_UPDATE_HI_DEN ;
                            }
                            else /* aj < 0 */
                            {
                                FIX_LO ;
                                /* update slope and compute den*/
                                SLOPE_UPDATE_LO_DEN ;
                            }
                        }
                        END_UNFIXED_LOOP ;
                    }
                }
                slope -= b ;

                /* update bracketting interval */
                if ( slope > NAPZERO ) /* optimal mult. to the right */
                {
                    lambdaL = lambda ;
                    dL = slope ;
                }
                else if ( slope < NAPZERO ) /* optimal mult. is to the left */
                {
                    lambdaR = lambda ;
                    dR = slope ;
                }
                else /* slope = 0 and lambda is optimal */
                {
                    status = NAPHEAP_STATUS_OK ;
                    if ( d_is_one )
                    {
                        /* compute optimal solution for unfixed variables */
                        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                            NAPFLOAT t = y [j] - lambda*a [j] ;
                            if ( loExists && (t < lo [j]) )
                            {
                                t = lo [j] ;
                            }
                            else if ( hiExists && (t > hi [j]) )
                            {
                                t = hi [j] ;
                            }
                            x [j] = t ;
                        END_LOOP ;
                    }
                    else
                    {
                        /* compute optimal solution for unfixed variables */
                        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                            NAPFLOAT t = (ay [j] - lambda)*ad [j] ;
                            if ( loExists && (t < lo [j]) )
                            {
                                t = lo [j] ;
                            }
                            else if ( hiExists && (t > hi [j]) )
                            {
                                t = hi [j] ;
                            }
                            x [j] = t ;
                        END_LOOP ;
                    }
                    break ;
                }

                /* all variables fixed and slope != 0 */
                if ( nuf == 0 )
                {
                    status = NAPHEAP_STATUS_INFEASIBLE ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }

                /* When no variables are fixed, stop the Newton iteration
                   and start napsearch. */
                if ( start_napsearch || (nuf == nk) )
                {
                    break ;
                }
            }
            Stat->nnewton = nnewton ;
            Stat->nsecant = nsecant ;
            Stat->nvarfix = nvarfix;
        }
        else /* variable fixing algorithm */
        {
            prevslope = NAPZERO ;  /* dummy value, do not exit 1st iteration*/

            /* Perform up to K iterations of the variable fixing algorithm */
            for (it = 1; it <= K; it++)
            {
                /* evaluate new lambda and the slope */
                lambda = (num-b)/den ;
                crossed = FALSE ;
                if ( slope*prevslope < NAPZERO )
                {
                    crossed = TRUE ;
                }
                prevslope = slope ;
                slope = NAPZERO ;
                if ( d_is_one )
                {
                    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                        const NAPFLOAT aj = a [j] ;
                        const NAPFLOAT t = y [j] - lambda*aj ;
                        if ( loExists && (t < lo [j]) )
                        {
                            x [j] = lo [j] ;
                            slope += aj*lo [j] ;
                        }
                        else if ( hiExists && (t > hi [j]) )
                        {
                            x [j] = hi [j] ;
                            slope += aj*hi [j] ;
                        }
                        else
                        {
                            slope += aj*t ;
                            x [j] = t ;
                        }
                    END_LOOP ;
                }
                else
                {
                    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                        const NAPFLOAT t = (ay [j] - lambda)*ad [j] ;
                        if ( loExists && (t < lo [j]) )
                        {
                            x [j] = lo [j] ;
                            slope += a [j]*lo [j] ;
                        }
                        else if ( hiExists && (t > hi [j]) )
                        {
                            x [j] = hi [j] ;
                            slope += a [j]*hi [j] ;
                        }
                        else
                        {
                            slope += a [j]*t ;
                            x [j] = t ;
                        }
                    END_LOOP ;
                }
                slope -= b ;

                if ( slope > NAPZERO )     /* optimal mult. is to the right */
                {
                    if ( lambdaL < lambda )
                    {
                        lambdaL = lambda ;
                        dL = slope ;
                    }
                    else
                    {
                        lambda = lambdaL ;
                        slope = dL ;
                    }

                    if ( it == K )
                    {
                        if ( nuf == 0 ) /* optimal solution found */
                        {
                            status = NAPHEAP_STATUS_OK ;
                            break ;
                        }
                        status = NAPHEAP_STATUS_KEEP_LOOKING ;
                        break ;
                    }
                    /* fix variables and compute next step */
                    LOOP_OVER_UNFIXED ;
                    {
                        const NAPFLOAT aj = a [j];
                        if ( aj > NAPZERO )
                        {
                            VAR_FIX_LO ;
                        }
                        else /* aj < NAPZERO */
                        {
                            VAR_FIX_HI ;
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else if ( slope < NAPZERO ) /* optimal mult. is to the left */
                {
                    if ( lambdaR > lambda )
                    {
                        lambdaR = lambda ;
                        dR = slope ;
                    }
                    else
                    {
                        lambda = lambdaR ;
                        slope = dR ;
                    }
                    if ( it == K )
                    {
                        status = NAPHEAP_STATUS_KEEP_LOOKING ;
                        break ;
                    }

                    /* fix variables and compute next step */
                    LOOP_OVER_UNFIXED ;
                    {
                        const NAPFLOAT aj = a [j];
                        if ( aj > NAPZERO )
                        {
                            VAR_FIX_HI ;
                        }
                        else /* aj < NAPZERO */
                        {
                            VAR_FIX_LO ;
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else /* optimal solution found (slope is zero) */
                {
                    status = NAPHEAP_STATUS_OK ;
                    break ;
                }

                /* all variables fixed and slope != 0 */
                if ( (nuf == 0) && (nkf == 0) )
                {
                    status = NAPHEAP_STATUS_INFEASIBLE ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }

                if ( nuf == nk ) /* no variables were fixed */
                {
                    /* optimal solution found */
                    status = NAPHEAP_STATUS_OK ;
                    break ;
                }
            }
            Stat->nvarfix = it ;
        }

        /* if optimal solution not found, perform breakpoint search */
        if ( status == NAPHEAP_STATUS_KEEP_LOOKING )
        {
            status = napsearch (x, &lambda, lambdaL, lambdaR, b, slope,
                                ay, ad, a, lo, hi, n, breakpts, breaknext,
                                nuf, &nkf, &nfree, &nbound, uf, kf,
                                free_heap, bound_heap, Stat, Parm,
                                loExists, hiExists) ;

            if ( status == NAPHEAP_STATUS_OK )
            {
                napsolution1 (x, y, d, a, lo, hi, lambda, slope, kf, nkf,
                     free_heap, bound_heap, nfree, nbound, d_is_one) ;
            }
        }
        else /* optimal solution found */
        {
            /* heaps not built, set any unfixed variables and free variables */
            napsolution (x, a, y, ay, ad, lo, hi, lambda, uf, kf, nuf, nkf,
                         loExists, hiExists, d_is_one) ;
        }
        Stat->nkf = nkf ;
    }
    else if ( d_is_zero )
    {
        /* ================================================================== */
        /* === case when all(d==0) holds ==================================== */
        /* ================================================================== */

        /* initialization of the slope variables */
        slopehi  = NAPZERO ; /* upper subdifferential at given lambda */
        slopelo  = NAPZERO ; /* lower subdifferential at given lambda */
        slope0   = NAPZERO ; /* terms with no break point at lambda=0 */
        slope0hi = NAPZERO ; /* upper subdifferential terms at lambda=0 */
        slope0lo = NAPZERO ; /* lower subdifferential terms at lambda=0 */

        /* eliminate variables, compute lambdaL/R, domain, range, slope
           at 0 and starting guess, get breakpts. */
        for (k = 0; k < n; k++)
        {
            const NAPINT j = k ;
            const NAPFLOAT aj = a [j] ;
            const NAPFLOAT yj = y [j] ;
            const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
            const NAPFLOAT hij = (hiExists) ? hi [j] :  NAPINF ;

            if ( loj >= hij )
            {
                if ( loj == hij )
                {
                    NAPFLOAT t = aj*loj ;
                    b -= t ;
                    x [j] = loj ;
                    continue ;
                }
                else
                {
                    status = NAPHEAP_STATUS_INVALID_BOUNDS ;
                    Stat->kerror = j ;
                    Stat->lobad = loj ;
                    Stat->hibad = hij ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }
            }
            else if ( aj == NAPZERO )
            {
                if ( yj > NAPZERO )
                {
                    if ( hij >= NAPINF )
                    {
                        status = NAPHEAP_STATUS_UNBOUNDED ;
                        return (nap_wrapup (status, napdata, lambda)) ;
                    }
                    x [j] = hij ;
                    continue ;
                }
                else if ( yj < NAPZERO )
                {
                    if ( loj <= -NAPINF )
                    {
                        status = NAPHEAP_STATUS_UNBOUNDED ;
                        return (nap_wrapup (status, napdata, lambda)) ;
                    }
                    x [j] = loj ;
                    continue ;
                }
            }
            else /* xj is not fixed */
            {
                NAPFLOAT s = yj/aj ;
                breakpts [j] = s ;
                if ( s > lambdaR ) lambdaR = s ;
                if ( s < lambdaL ) lambdaL = s ;

                /* update the domain of dual function */
                if ( aj > NAPZERO )
                {
                    if ( (hij < NAPINF) && (maxax < NAPINF) )
                    {
                        maxax += aj*hij ;
                    }
                    else
                    {
                        maxax  = NAPINF ;
                    }
                    if ( (loj > -NAPINF) && (minax > -NAPINF) )
                    {
                        minax += aj*loj ;
                    }
                    else
                    {
                        minax = -NAPINF ;
                    }
                    if ( loj <= -NAPINF ) domhi = MIN (domhi, s) ;
                    if ( hij >=  NAPINF ) domlo = MAX (domlo, s) ;
                }
                else /* aj < 0 */
                {

                    if ( (loj > -NAPINF) && (maxax < NAPINF) )
                    {
                        maxax += aj*loj ;
                    }
                    else
                    {
                        maxax  = NAPINF ;
                    }
                    if ( (hij < NAPINF) && (minax > -NAPINF) )
                    {
                        minax += aj*hij ;
                    }
                    else
                    {
                        minax = -NAPINF ;
                    }
                    if ( loj <= -NAPINF ) domlo = MAX (domlo, s) ;
                    if ( hij >=  NAPINF ) domhi = MIN (domhi, s) ;
                }

                /* update the slope of dual function at lambda */
                if ( use_lambda )
                {
                    if ( s < lambda )
                    {
                        NAPFLOAT xj ;
                        if ( aj > NAPZERO ) xj = loj ;
                        else                xj = hij ;
                        slope += aj*xj ;
                    }
                    else if ( s > lambda )
                    {
                        NAPFLOAT xj ;
                        if ( aj > NAPZERO ) xj = hij ;
                        else                xj = loj ;
                        slope += aj*xj ;
                    }
                    else /* lambda is a break point */
                    {
                        if ( aj > NAPZERO )
                        {
                            slopehi += aj*hij ;
                            slopelo += aj*loj ;
                        }
                        else
                        {
                            slopelo += aj*hij ;
                            slopehi += aj*loj ;
                        }
                    }
                }

                /* update the slope of the dual function at lambda = 0 */
                if      ( yj > NAPZERO ) slope0 += aj*hij ;
                else if ( yj < NAPZERO ) slope0 += aj*loj ;
                else
                {
                    if ( aj > NAPZERO )
                    {
                        slope0hi += aj*hij ;
                        slope0lo += aj*loj ;
                    }
                    else
                    {
                        slope0hi += aj*loj ;
                        slope0lo += aj*hij ;
                    }
                }
                uf [nuf] = j ;
                nuf++ ;
            }
        }

        if ( (minax - b > bhi) || (maxax - b < blo) ) /* problem infeasible */
        {
            nap_infeasible (x, a, lo, hi, uf, nuf, minax, maxax, blo, bhi) ;
            status = NAPHEAP_STATUS_INFEASIBLE ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        if ( domlo > domhi ) /* dual function is -inf */
        {
            status = NAPHEAP_STATUS_UNBOUNDED ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }
        if ( use_lambda )
        {
            if ( (lambda < domlo) || (lambda > domhi) )
            {
                use_lambda = FALSE ; /* cannot use lambda if outside domain */
            }
        }

        /* if 0 in [domlo, domhi], then use slope at 0 to choose b */
        if ( (domlo <= NAPZERO) && (domhi >= NAPZERO) )
        {
            if ( slope0 + slope0hi < blo + b ) /* optimal lambda < 0 */
            {
                b += blo ;
                if ( lambdaR >= NAPZERO )
                {
                    lambdaR = NAPZERO ; /* lambda = 0 is closer than lambdaR */
                    dR = slope0 + slope0hi - b ;
                    Rout = FALSE ; /* optimal lambda left of lambdaR */
                    dL = maxax - b ;
                    Lout = TRUE ;
                }
                else /* lambdaR is closer to optimal lambda */
                {
                    dR = minax - b ;
                    /* lambdaR and lambdaL outside interval containing lambda */
                    Rout = TRUE ;
                    Lout = TRUE ;
                    if ( lambdaL < domlo )
                    {
                        lambdaL = domlo ; /* domlo closer to optimal lambda */
                        dL = NAPINF ;
                    }
                    else dL = maxax - b ;
                }
            }
            else if ( slope0 + slope0lo > b + bhi ) /* optimal lambda > 0 */
            {
                b += bhi ;
                if ( lambdaL <= NAPZERO )
                {
                    lambdaL = NAPZERO ; /* lambda = 0 is closer than lambdaL */
                    dL = slope0 + slope0lo - b ;
                    Lout = FALSE ;
                    dR = minax - b ;
                    Rout = TRUE ;
                }
                else /* lambdaL is closer to optimal lambda */
                {
                    dL = maxax - b ;
                    /* lambdaR and lambdaL outside interval containing lambda */
                    Lout = TRUE ;
                    Rout = TRUE ;
                    if ( lambdaR > domhi )
                    {
                        lambdaR = domhi ;
                        dR = -NAPINF ;
                    }
                    else dR = minax - b ;
                }
            }
            else /* lambda = 0 optimal, blo <= a'x <= bhi */
            {
                lambda = NAPZERO ;
                b -= slope0 ;
                slopehi = slope0hi ;
                slopelo = slope0lo ;
                LOOP_OVER_UNFIXED ;
                {
                    if ( y [j] < NAPZERO )
                    {
                        x [j] = lo [j] ;
                        continue ;
                    }
                    else if ( y [j] > NAPZERO )
                    {
                        x [j] = hi [j] ;
                        continue ;
                    }
                }
                END_UNFIXED_LOOP ;

                /* Determine the target b = a'x to have the smallest magnitude
                   while satisfying the constraint that blo <= b <= bhi.
                   Below, b initially stores -sum a_i x_i with x_i already at
                   a bound*/
                if ( (slopelo >= b+blo) && (slopehi <= b+bhi) )
                {
                    if ( fabs (slopelo) <= fabs (slopehi) )
                    {
                        b = slopelo ;
                    }
                    else
                    {
                        b = slopehi ;
                    }
                }
                else if ( slopehi > b + bhi )
                {
                    if ( slopelo >= b + blo )
                    {
                        if ( fabs (slopelo) <= fabs (b + bhi) )
                        {
                            b = slopelo ;
                        }
                        else
                        {
                            b += bhi ;
                        }
                    }
                    else if ( fabs (b+blo) <= fabs (b+bhi) )
                    {
                        b += blo ;
                    }
                    else
                    {
                        b += bhi ;
                    }
                }
                else
                {
                    if ( fabs (slopehi) <= fabs (b+blo) )
                    {
                        b = slopehi ;
                    }
                    else
                    {
                        b += blo ;
                    }
                }
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
        }
        else /* lambda = 0 outside domain [domlo, domhi] of dual function */
        {
            if ( domlo > NAPZERO )
            {
                b += bhi ;
                lambdaL = domlo ;
                dL = NAPINF ;
                Lout = TRUE ;
                Rout = TRUE ;
                if ( domhi < NAPINF )
                {
                    lambdaR = domhi ;
                    dR = -NAPINF ;
                }
                else
                {
                    if ( minax > -NAPINF ) dR = minax - b ;
                    else                   dR = -NAPINF ;
                }
            }
            else /* domhi < NAPZERO */
            {
                b += blo ;
                lambdaR = domhi ;
                dR = -NAPINF ;
                Rout = TRUE ;
                Lout = TRUE ;
                if ( domlo > -NAPINF )
                {
                    lambdaL = domlo ;
                    dL = NAPINF ;
                }
                else
                {
                    if ( maxax < NAPINF ) dL = maxax - b ;
                    else                  dL = NAPINF ;
                }
            }
            if ( domlo == domhi )
            {
                lambda = domlo ;
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT s = breakpts [j] ;
                    const NAPFLOAT aj = a [j] ;
                    if ( s < lambda )
                    {
                        NAPFLOAT t ;
                        if ( aj > NAPZERO ) t = lo [j] ;
                        else                t = hi [j] ;
                        x [j] = t ;
                        b -= aj*t ;
                        continue ;
                    }
                    else if ( s > lambda )
                    {
                        NAPFLOAT t ;
                        if ( aj > NAPZERO ) t = hi [j] ;
                        else                t = lo [j] ;
                        x [j] = t ;
                        b -= aj*t ;
                        continue ;
                    }
                }
                END_UNFIXED_LOOP ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
        }

        /* b has been set, adjust slope */
        slope0 -= b ;

        /* if lambda has been given, check that it lies in the domain of the
           dual function, and exploit its associated slope */
        recompute_slope = FALSE ;
        if ( use_lambda )
        {
            if ( (lambda >= lambdaL) && (lambda <= lambdaR) )
            {
                slope -= b ;
                if ( slope + slopelo > NAPZERO )  /* lambda* is to right */
                {
                    goright = TRUE ;
                    slope += slopelo ;
                    dL = slope ;
                    lambdaL = lambda ;
                    Lout = FALSE ;
                }
                else if ( slope + slopehi < NAPZERO ) /* lambda* is to left */
                {
                    goright = FALSE ;
                    slope += slopehi ;
                    dR = slope ;
                    lambdaR = lambda ;
                    Rout = FALSE ;
                }
                else
                {
                    /* lambda is optimal */
                    napfix0 (x, a, lo, hi, &b, lambda, uf, &nuf, breakpts) ;
                    napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                                  free_heap, bound_heap, loExists, hiExists) ;
                    ASSERT (status == NAPHEAP_STATUS_OK) ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }
            }
            else if ( lambda < lambdaL )
            {
                goright = TRUE ; /* optimal multiplier to the right */
                lambda = lambdaL ;
                if ( Lout ) recompute_slope = TRUE ; /* lambda outside domain */
                else        slope = dL ;
            }
            else /* ( lambda > lambdaR ) */
            {
                goright = FALSE ; /* optimal multiplier to the left */
                lambda = lambdaR ;
                if ( Rout ) recompute_slope = TRUE ;
                else        slope = dR ;
            }
        }
        else if ( K == 0 ) /* if no lambda given and K = 0, use smaller slope */
        {
            if ( dL < -dR )
            {
                lambda = lambdaL ;
                goright = TRUE ;
                if ( Lout ) recompute_slope = TRUE ;
                else        slope = dL ;
            }
            else
            {
                if ( lambdaR < NAPINF )
                {
                    lambda = lambdaR ;
                    goright = FALSE ;
                    if ( Rout ) recompute_slope = TRUE ;
                    else        slope = dR ;
                }
                else
                {
                    lambda = lambdaL ;
                    goright = TRUE ;
                    if ( Lout ) recompute_slope = TRUE ;
                    else        slope = dL ;
                }
            }
        }

        if ( K == 0 ) /* use break point search algorithm */
        {
            #ifdef NAPSACK_BRUTAL
            /* !!!!!!!!! mess up the slope for debugging !!!!!!!!!! */
            /* This is only for extensive debugging, not for production use. */
            if ( Parm->refine && n > 3 )
            {
                if ( slope > 0 )
                {
                    if ( a [3] > 0 ) slope += 1 ;
                    else             slope /= 2 ;
                }
                else
                {
                    if ( a [3] > 0 ) slope -= 1 ;
                    else             slope /= 2 ;
                }
            }
            #endif

            napsearch0 (x, &lambda, lambdaL, lambdaR, &b,
                                    &slope, &slopelo, &slopehi, n, a, lo, hi,
                                    breakpts, uf, &nuf, bound_heap, goright,
                                    Stat, recompute_slope, Parm,
                                    loExists, hiExists) ;
            napfix0 (x, a, lo, hi, &b, lambda, uf, &nuf, breakpts) ;
            napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf, free_heap,
                          bound_heap, loExists, hiExists) ;
            ASSERT (status == NAPHEAP_STATUS_OK) ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        /* K > 0, evaluate num and den and prepare for variable fixing over the
           domain of the dual function */
        if ( K == 1 ) /* do not save aj*yj and aj*aj */
        {
            LOOP_OVER_UNFIXED ;
            {
                /* if j is in the list of undetermined variables,
                   then breakpts [j] has been computed above */
                const NAPFLOAT t = breakpts [j] ;
                const NAPFLOAT aj = a [j] ;
                if ( t < lambdaL ) /* xj is fixed */
                {
                    NAPFLOAT xj ;
                    if ( aj > NAPZERO ) xj = lo [j] ;
                    else                xj = hi [j] ;
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else if ( t > lambdaR ) /* xj is fixed */
                {
                    NAPFLOAT xj ;
                    if ( aj > NAPZERO ) xj = hi [j] ;
                    else                xj = lo [j] ;
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else
                {
                    num += aj*y [j] ;
                    den += aj*aj ;
                }
            }
            END_UNFIXED_LOOP ;
        }
        else /* K > 1, also save aj*yj and aj*aj */
        {
            LOOP_OVER_UNFIXED ;
            {
                const NAPFLOAT aj = a [j] ;
                NAPFLOAT t = breakpts [j] ;
                if ( t < lambdaL ) /* xj is fixed */
                {
                    NAPFLOAT xj ;
                    if ( aj > NAPZERO ) xj = lo [j] ;
                    else                xj = hi [j] ;
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else if ( t > lambdaR ) /* xj is fixed */
                {
                    NAPFLOAT xj ;
                    if ( aj > NAPZERO ) xj = hi [j] ;
                    else                xj = lo [j] ;
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else
                {
                    t = aj*y [j] ;
                    ady [j] = t ;
                    num += t ;
                    t = aj*aj ;
                    ada [j] = t ;
                    den += t ;
                }
            }
            END_UNFIXED_LOOP ;
        }

        /* perform K iterations of variable fixing algorithm */
        for (it = 1; it <= K; it++)
        {
            lambda = num/den ;
            if ( lambda < lambdaL )
            {
                lambda = lambdaL ;
            }
            else if ( lambda > lambdaR )
            {
                lambda = lambdaR ;
            }
            /* slope corresponds to terms with no break point at lambda */
            slope = NAPZERO ;
            /* upper subdifferential terms associated with lambda */
            slopehi = NAPZERO ;
            /* lower subdifferential terms associated with lambda */
            slopelo = NAPZERO ;
            LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                const NAPFLOAT t = breakpts [j] ;
                const NAPFLOAT aj = a [j] ;
                if ( aj > NAPZERO )
                {

                    if      ( lambda > t ) slope += aj*lo [j] ;
                    else if ( lambda < t ) slope += aj*hi [j] ;
                    else
                    {
                        slopehi += aj*hi [j] ;
                        slopelo += aj*lo [j] ;
                    }
                }
                else
                {

                    if      ( lambda > t ) slope += aj*hi [j] ;
                    else if ( lambda < t ) slope += aj*lo [j] ;
                    else
                    {
                        slopehi += aj*lo [j] ;
                        slopelo += aj*hi [j] ;
                    }
                }
            END_LOOP
            slope -= b ;

            /* check for optimal solution */
            if ( (slope+slopelo <= NAPZERO) && (slope + slopehi >= NAPZERO) )
            {
                napfix0 (x, a, lo, hi, &b, lambda, uf, &nuf, breakpts) ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                Stat->nvarfix = it ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }

            if ( slope + slopelo > NAPZERO )  /* optimal mult. is to right */
            {
                if ( lambdaL < lambda )
                {
                    lambdaL = lambda ;
                    dL = slope + slopelo ;
                    Lout = FALSE ;
                }
                else lambda = lambdaL ;
                if ( it == K ) break ;
                LOOP_OVER_UNFIXED ;
                {
                    if ( breakpts [j] < lambda ) /* xj is fixed */
                    {
                        NAPFLOAT xj ;
                        const NAPFLOAT aj = a [j] ;
                        if ( aj > NAPZERO ) xj = lo [j] ;
                        else                xj = hi [j] ;
                        b -= aj*xj ;
                        x [j] = xj ;
                        num -= ady [j] ;
                        den -= ada [j] ;
                        continue ;
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else if ( slope + slopehi < NAPZERO ) /* optimal mult. to left */
            {
                if ( lambdaR > lambda )
                {
                    lambdaR = lambda ;
                    dR = slope + slopehi ;
                    Rout = FALSE ;
                }
                else lambda = lambdaR ;
                if ( it == K ) break ;
                LOOP_OVER_UNFIXED ;
                {
                    if ( breakpts [j] > lambda ) /* xj is fixed */
                    {
                        NAPFLOAT xj ;
                        const NAPFLOAT aj = a [j] ;
                        if ( aj > NAPZERO ) xj = hi [j] ;
                        else                xj = lo [j] ;
                        x [j] = xj ;
                        b -= aj*xj ;
                        num -= ady [j] ;
                        den -= ada [j] ;
                        continue ;
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else    /* optimal solution found */
            {
                napfix0 (x, a, lo, hi, &b, lambda, uf, &nuf, breakpts) ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                Stat->nvarfix = it ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
            if ( nuf == nk ) break ; /* nothing was fixed */
        }
        Stat->nvarfix = K ;
        if ( dL < -dR ) /* go right */
        {
            lambda = lambdaL ;
            slope = dL ;
            goright = TRUE ;
            if ( Lout ) recompute_slope = TRUE ;
        }
        else /* go left unless lambdaR = INF */
        {
            if ( lambdaR < NAPINF )
            {
                lambda = lambdaR ;
                slope = dR ;
                goright = FALSE ;
                if ( Rout ) recompute_slope = TRUE ;
            }
            else
            {
                lambda = lambdaL ;
                slope = dL ;
                goright = TRUE ;
                if ( Lout ) recompute_slope = TRUE ;
            }
        }

        #ifdef NAPSACK_BRUTAL
        /* !!!!!!!!! mess up the slope for debugging !!!!!!!!!! */
        /* This is only for extensive debugging, not for production use. */
        if ( Parm->refine && n > 3 )
        {
            if ( slope > 0 )
            {
                if ( a [3] > 0 ) slope += 1 ;
                else             slope /= 2 ;
            }
            else
            {
                if ( a [3] > 0 ) slope -= 1 ;
                else             slope /= 2 ;
            }
        }
        #endif

        napsearch0 (x, &lambda, lambdaL, lambdaR, &b,
                    &slope, &slopelo, &slopehi, n, a, lo, hi,
                    breakpts, uf, &nuf, bound_heap, goright,
                    Stat, recompute_slope, Parm,
                    loExists, hiExists) ;
        napfix0 (x, a, lo, hi, &b, lambda, uf, &nuf, breakpts) ;
        napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                      free_heap, bound_heap, loExists, hiExists) ;

    }
    else /* !d_is_zero && !d_is_pos (diagonal not fully 0 or fully positive) */
    {
        /* ================================================================== */
        /* === case for general d =========================================== */
        /* ================================================================== */

        /* initialization of the slope variables */
        slopehi  = NAPZERO ; /* upper subdifferential at given lambda */
        slopelo  = NAPZERO ; /* lower subdifferential at given lambda */
        slope0 = NAPZERO ;   /* terms with no break point at lambda=0 */
        slope0hi = NAPZERO ; /* upper subdifferential terms at lambda=0 */
        slope0lo = NAPZERO ; /* lower subdifferential terms at lambda=0 */
        for (k = 0; k < n; k++ )
        {
            const NAPINT j = k ;
            const NAPFLOAT dj = d [j] ;
            if ( dj < 0 )
            {
                status = NAPHEAP_STATUS_INVALID_D ;
                Stat->kerror = j ;
                Stat->dbad = d [j] ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
            const NAPFLOAT aj = a [j] ;
            const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
            const NAPFLOAT hij = (hiExists) ? hi [j] :  NAPINF ;
            NAPFLOAT yj = y [j] ;

            if ( loj >= hij )
            {
                if ( loj == hij )
                {
                    NAPFLOAT t = aj*loj ;
                    b -= t ;
                    x [j] = loj ;
                    continue ;
                }
                else
                {
                    status = NAPHEAP_STATUS_INVALID_BOUNDS ;
                    Stat->kerror = j ;
                    Stat->lobad = loj ;
                    Stat->hibad = hij ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }
            }
            if ( dj ) /* dj > 0 */
            {
                if ( aj == NAPZERO )
                {
                    NAPFLOAT xj ;
                    xj = yj/dj ;
                    if      ( xj < loj ) xj = loj ;
                    else if ( xj > hij ) xj = hij ;
                    x [j] = xj ;
                    continue ;
                }
                else
                {
                    if ( aj > NAPZERO )
                    {
                        if ( (hij < NAPINF) && (maxax < NAPINF) )
                        {
                            maxax += aj*hij ;
                        }
                        else
                        {
                            maxax  = NAPINF ;
                        }
                        if ( (loj > -NAPINF) && (minax > -NAPINF) )
                        {
                            minax += aj*loj ;
                        }
                        else
                        {
                            minax = -NAPINF ;
                        }
                        /* also store max and min break points */
                        NAPFLOAT t = (yj - loj*dj)/aj ;
                        if ( t > lambdaR )
                        {
                            if ( loj > -NAPINF ) lambdaR = t ;
                            else                 lambdaR = NAPINF ;
                        }
                        t = (yj - hij*dj)/aj ;
                        if ( t < lambdaL )
                        {
                            if ( hij < NAPINF ) lambdaL = t ;
                            else                lambdaL = -NAPINF ;
                        }
                    }
                    else
                    {
                        if ( (loj > -NAPINF) && (maxax < NAPINF) )
                        {
                            maxax += aj*loj ;
                        }
                        else
                        {
                            maxax  = NAPINF ;
                        }
                        if ( (hij < NAPINF) && (minax > -NAPINF) )
                        {
                            minax += aj*hij ;
                        }
                        else
                        {
                            minax = -NAPINF ;
                        }
                        /* also store max and min break points */
                        NAPFLOAT t = (yj - hij*dj)/aj ;
                        if ( t > lambdaR )
                        {
                            if ( hij < NAPINF ) lambdaR = t ;
                            else                lambdaR = NAPINF ;
                        }
                        t = (yj - loj*dj)/aj ;
                        if ( t < lambdaL )
                        {
                            if ( loj > -NAPINF ) lambdaL = t ;
                            else                 lambdaL = -NAPINF ;
                        }
                    }

                    /* slope at lambda */
                    if ( use_lambda )
                    {
                        NAPFLOAT t = (yj - lambda*aj)/dj ;
                        if      ( t < loj ) t = loj ;
                        else if ( t > hij ) t = hij ;
                        slope += aj*t ;
                    }

                    /* slope at lambda = 0 */
                    yj /= dj ; /* yj now stores yj/dj */
                    if      ( yj < loj ) yj = loj ;
                    else if ( yj > hij ) yj = hij ;
                    slope0 += aj*yj ;
                }
            }
            else /* dj = 0 */
            {
                if ( aj == NAPZERO )
                {
                    if ( yj > NAPZERO )
                    {
                        if ( hij >= NAPINF )
                        {
                            status = NAPHEAP_STATUS_UNBOUNDED ;
                            return (nap_wrapup (status, napdata, lambda)) ;
                        }
                        x [j] = hij ;
                    }
                    else if ( yj < NAPZERO )
                    {
                        if ( loj <= -NAPINF )
                        {
                            status = NAPHEAP_STATUS_UNBOUNDED ;
                            return (nap_wrapup (status, napdata, lambda)) ;
                        }
                        x [j] = loj ;
                    }
                    continue ;
                }
                else
                {
                    NAPFLOAT s = yj/aj ;
                    breakpts [j] = s ;
                    if ( s > lambdaR ) lambdaR = s ;
                    if ( s < lambdaL ) lambdaL = s ;

                    /* update the domain of dual function */
                    if ( aj > NAPZERO )
                    {
                        if ( (hij < NAPINF) && (maxax < NAPINF) )
                        {
                            maxax += aj*hij ;
                        }
                        else
                        {
                            maxax  = NAPINF ;
                        }
                        if ( (loj > -NAPINF) && (minax > -NAPINF) )
                        {
                            minax += aj*loj ;
                        }
                        else
                        {
                            minax = -NAPINF ;
                        }
                        if ( loj <= -NAPINF ) domhi = MIN (domhi, s) ;
                        if ( hij >=  NAPINF ) domlo = MAX (domlo, s) ;
                    }
                    else /* aj < 0 */
                    {
                        if ( (loj > -NAPINF) && (maxax < NAPINF) )
                        {
                            maxax += aj*loj ;
                        }
                        else
                        {
                            maxax  = NAPINF ;
                        }
                        if ( (hij < NAPINF) && (minax > -NAPINF) )
                        {
                            minax += aj*hij ;
                        }
                        else
                        {
                            minax = -NAPINF ;
                        }
                        if ( loj <= -NAPINF ) domlo = MAX (domlo, s) ;
                        if ( hij >=  NAPINF ) domhi = MIN (domhi, s) ;
                    }

                    /* compute slope at lambda */
                    if ( use_lambda )
                    {
                        if ( s < lambda )
                        {
                            NAPFLOAT xj ;
                            if ( aj > NAPZERO ) xj = loj ;
                            else                xj = hij ;
                            slope += aj*xj ;
                        }
                        else if ( s > lambda )
                        {
                            NAPFLOAT xj ;
                            if ( aj > NAPZERO ) xj = hij ;
                            else                xj = loj ;
                            slope += aj*xj ;
                        }
                        else /* lambda is a break point */
                        {
                            if ( aj > NAPZERO )
                            {
                                slopehi += aj*hij ;
                                slopelo += aj*loj ;
                            }
                            else
                            {
                                slopelo += aj*hij ;
                                slopehi += aj*loj ;
                            }
                        }
                    }

                    /* compute slope at lambda = 0 */
                    if      ( yj > NAPZERO ) slope0 += aj*hij ;
                    else if ( yj < NAPZERO ) slope0 += aj*loj ;
                    else
                    {
                        if ( aj > NAPZERO )
                        {
                            slope0hi += aj*hij ;
                            slope0lo += aj*loj ;
                        }
                        else
                        {
                            slope0lo += aj*hij ;
                            slope0hi += aj*loj ;
                        }
                    }
                }
            }
            uf [nuf] = j ;
            nuf++ ;
        }

        /* check if problem feasible */
        if ( (minax - b > bhi) || (maxax - b < blo) )
        {
            nap_infeasible (x, a, lo, hi, uf, nuf, minax, maxax, blo, bhi) ;
            status = NAPHEAP_STATUS_INFEASIBLE ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        if ( domlo > domhi )
        {
            status = NAPHEAP_STATUS_UNBOUNDED ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }
       if ( use_lambda )
       {
           if ( (lambda < domlo) || (lambda > domhi) )
           {
               use_lambda = FALSE ; /* cannot use lambda if outside domain */
           }
       }

        /* if 0 in [domlo, domhi], then use slope at 0 to choose b */
        if ( (domlo <= NAPZERO) && (domhi >= NAPZERO) )
        {
            if ( slope0 + slope0hi < blo + b ) /* optimal lambda < 0 */
            {
                b += blo ;
                if ( lambdaR >= NAPZERO )
                {
                    lambdaR = NAPZERO ; /* lambda = 0 is closer than lambdaR */
                    dR = slope0 + slope0hi - b ;
                    Rout = FALSE ; /* optimal lambda left of lambdaR */
                    if ( lambdaL > -NAPINF ) dL = maxax - b ;
                    else                     dL = NAPINF ;
                    Lout = TRUE ;
                }
                else /* lambdaR is closer to optimal lambda */
                {
                    dR = minax - b ;
                    /* lambdaR and lambdaL outside interval containing lambda */
                    Rout = TRUE ;
                    Lout = TRUE ;
                    if ( lambdaL < domlo )
                    {
                        lambdaL = domlo ; /* domlo closer to optimal lambda */
                        dL = NAPINF ;
                    }
                    else dL = maxax - b ;
                }
            }
            else if ( slope0 + slope0lo > b + bhi ) /* optimal lambda > 0 */
            {
                b += bhi ;
                if ( lambdaL <= NAPZERO )
                {
                    lambdaL = NAPZERO ; /* lambda = 0 is closer than lambdaL */
                    dL = slope0 + slope0lo - b ;
                    Lout = FALSE ;
                    if ( lambdaR < NAPINF ) dR = minax - b ;
                    else                    dR = -NAPINF ;
                    Rout = TRUE ;
                }
                else /* lambdaL is closer to optimal lambda */
                {
                    dL = maxax - b ;
                    /* lambdaR and lambdaL outside interval containing lambda */
                    Lout = TRUE ;
                    Rout = TRUE ;
                    if ( lambdaR > domhi )
                    {
                        lambdaR = domhi ;
                        dR = -NAPINF ;
                    }
                    else dR = minax - b ;
                }
            }
            else /* lambda = 0 optimal, blo <= a'x <= bhi */
            {
                lambda = NAPZERO ;
                b -= slope0 ;
                slopehi = slope0hi ;
                slopelo = slope0lo ;
                LOOP_OVER_UNFIXED ;
                {
                    if ( d [j] > NAPZERO )
                    {
                        NAPFLOAT xj = y [j]/d [j] ;
                        if      ( loExists && (xj < lo [j]) ) x [j] = lo [j] ;
                        else if ( hiExists && (xj > hi [j]) ) x [j] = hi [j] ;
                        else                                  x [j] = xj ;
                        continue ;
                    }
                    else /* dj = 0 */
                    {
                        if ( y [j] < NAPZERO )
                        {
                            x [j] = lo [j] ;
                            continue ;
                        }
                        else if ( y [j] > NAPZERO )
                        {
                            x [j] = hi [j] ;
                            continue ;
                        }
                    }
                }
                END_UNFIXED_LOOP ;

                /* Determine the target b = a'x to have the smallest magnitude
                   while satisfying the constraint that blo <= b <= bhi.
                   Below, b initial stores -sum a_i x_i with x_i already at
                   a bound*/
                if ( (slopelo >= b+blo) && (slopehi <= b+bhi) )
                {
                    if ( fabs (slopelo) <= fabs (slopehi) )
                    {
                        b = slopelo ;
                    }
                    else
                    {
                        b = slopehi ;
                    }
                }
                else if ( slopehi > b + bhi )
                {
                    if ( slopelo >= b + blo )
                    {
                        if ( fabs (slopelo) <= fabs (b + bhi) )
                        {
                            b = slopelo ;
                        }
                        else
                        {
                            b += bhi ;
                        }
                    }
                    else if ( fabs (b+blo) <= fabs (b+bhi) )
                    {
                        b += blo ;
                    }
                    else
                    {
                        b += bhi ;
                    }
                }
                else
                {
                    if ( fabs (slopehi) <= fabs (b+blo) )
                    {
                        b = slopehi ;
                    }
                    else
                    {
                        b += blo ;
                    }
                }

                /* fix all variables for which the break point != lambda */
                napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                         loExists, hiExists, breakpts) ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
        }
        else /* lambda = 0 outside domain [domlo, domhi] of dual function */
        {
            if ( domlo > NAPZERO )
            {
                b += bhi ;
                lambdaL = domlo ;
                dL = NAPINF ;
                Lout = TRUE ;
                Rout = TRUE ;
                if ( domhi < NAPINF )
                {
                    lambdaR = domhi ;
                    dR = -NAPINF ;
                }
                else
                {
                    if ( minax > -NAPINF ) dR = minax - b ;
                    else                   dR = -NAPINF ;
                }
            }
            else /* domhi < NAPZERO */
            {
                b += blo ;
                lambdaR = domhi ;
                dR = -NAPINF ;
                Rout = TRUE ;
                Lout = TRUE ;
                if ( domlo > -NAPINF )
                {
                    lambdaL = domlo ;
                    dL = NAPINF ;
                }
                else
                {
                    if ( maxax < NAPINF ) dL = maxax - b ;
                    else                  dL = NAPINF ;
                }
            }
            if ( domlo == domhi )
            {
                lambda = domlo ;
                napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                         loExists, hiExists, breakpts) ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
                ASSERT (status == NAPHEAP_STATUS_OK) ;
                return (nap_wrapup (status, napdata, lambda)) ;
            }
        }

        /* b has been set, adjust slope */
        slope0 -= b ;

        /* if lambda has been given, check that it lies in the domain of the
           dual function, and exploit its associated slope */
        recompute_slope = FALSE ;
        if ( use_lambda )
        {
            if ( (lambda >= lambdaL) && (lambda <= lambdaR) )
            {
                slope -= b ;
                if ( slope + slopelo > NAPZERO )  /* opt lambda is to right */
                {
                    goright = TRUE ;
                    slope += slopelo ;
                    dL = slope ;
                    lambdaL = lambda ;
                    Lout = FALSE ;
                }
                else if ( slope + slopehi < NAPZERO ) /* opt lambda is to left*/
                {
                    goright = FALSE ;
                    slope += slopehi ;
                    dR = slope ;
                    lambdaR = lambda ;
                    Rout = FALSE ;
                }
                else
                {
                    /* lambda is optimal */
                    napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                             loExists, hiExists, breakpts);
                    napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                                  free_heap, bound_heap, loExists, hiExists) ;
                    ASSERT (status == NAPHEAP_STATUS_OK) ;
                    return (nap_wrapup (status, napdata, lambda)) ;
                }
            }
            else if ( lambda < lambdaL ) /* optimal multiplier to the right */
            {
                goright = TRUE ;
                lambda = lambdaL ;
                if ( Lout ) recompute_slope = TRUE ; /* lambda outside domain */
                else        slope = dL ;
            }
            else /* ( lambda > lambdaR )  optimal multiplier to the left */
            {
                goright = FALSE ;
                lambda = lambdaR ;
                if ( Rout ) recompute_slope = TRUE ;
                else        slope = dR ;
            }
        }
        else if ( K == 0 ) /* if no lambda given and K = 0, use smaller slope */
        {
            if ( dL < -dR )
            {
                lambda = lambdaL ;
                goright = TRUE ;
                if ( Lout ) recompute_slope = TRUE ;
                else        slope = dL ;
            }
            else
            {
                if ( lambdaR < NAPINF )
                {
                    lambda = lambdaR ;
                    goright = FALSE ;
                    if ( Rout ) recompute_slope = TRUE ;
                    else        slope = dR ;
                }
                else
                {
                    lambda = lambdaL ;
                    goright = TRUE ;
                    if ( Lout ) recompute_slope = TRUE ;
                    else        slope = dL ;
                }
            }
        }

        if ( K == 0 ) /* use break point search algorithm */
        {

            #ifdef NAPSACK_BRUTAL
            /* !!!!!!!!! mess up the slope for debugging !!!!!!!!!! */
            /* This is only for extensive debugging, not for production use. */
            if ( Parm->refine && n > 3 )
            {
                if ( slope > 0 )
                {
                    if ( a [3] > 0 ) slope += 5 ;
                    else             slope /= 4 ;
                }
                else
                {
                    if ( a [3] > 0 ) slope -= 5 ;
                    else             slope /= 4 ;
                }
            }
            #endif

            napsearch1 (x, &lambda, lambdaL, lambdaR, &b, &slope, &slopelo,
                        &slopehi, y, d, a, lo, hi, n, K, breakpts, uf, &nuf,
                        free_heap, bound_heap, goright, Stat, br_lo, br_hi,
                        recompute_slope, Parm, loExists, hiExists) ;
            /* fix all variables for which the break point != lambda */
            napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                     loExists, hiExists, breakpts) ;

            /* determine the variables for which di = 0 and the
               associated break point = lambda */
            napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                          free_heap, bound_heap, loExists, hiExists) ;
            ASSERT (status == NAPHEAP_STATUS_OK) ;
            return (nap_wrapup (status, napdata, lambda)) ;
        }

        /* K > 0, evaluate num and den and prepare for variable fixing over the
           domain of the dual function */
        if ( K > 1 ) k_gt_1 = TRUE ;
        else         k_gt_1 = FALSE ;
        LOOP_OVER_UNFIXED ;
        {
            const NAPFLOAT aj = a [j] ;
            const NAPFLOAT dj = d [j] ;
            if ( dj > NAPZERO )
            {
                const NAPFLOAT yj = y [j] ;
                if ( aj > NAPZERO )
                {
                    const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                    const NAPFLOAT r = (yj - loj*dj)/aj ; /* high break point */
                    if ( r < lambdaL )   /* j is fixed */
                    {
                        b -= aj*loj ;
                        x [j] = loj ;
                        continue ;
                    }

                    const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                    const NAPFLOAT s = (yj - hij*dj)/aj ; /* low break point */
                    if ( s > lambdaR )   /* j is fixed */
                    {
                        b -= aj*hij ;
                        x [j] = hij ;
                        continue ;
                    }
                    br_hi [j] = r ;
                    br_lo [j] = s ;
                }
                else
                {
                    const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                    const NAPFLOAT r = (yj - loj*dj)/aj ; /* low break point */
                    if ( r > lambdaR )   /* j is fixed */
                    {
                        b -= aj*loj ;
                        x [j] = loj ;
                        continue ;
                    }

                    const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                    const NAPFLOAT s = (yj - hij*dj)/aj ; /* high break point */
                    if ( s < lambdaL )   /* j is fixed */
                    {
                        b -= aj*hij ;
                        x [j] = hij ;
                        continue ;
                    }
                    br_hi [j] = s ;
                    br_lo [j] = r ;
                }
            }
            else /* dj = 0 */
            {
                NAPFLOAT xj ;
                if ( breakpts [j] < lambdaL ) /* xj is fixed */
                {
                    if ( aj > NAPZERO )
                    {
                        xj = lo [j] ;
                    }
                    else
                    {
                        xj = hi [j] ;
                    }
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else if ( breakpts [j] > lambdaR ) /* xj is fixed */
                {
                    if ( aj > NAPZERO )
                    {
                        xj = hi [j] ;
                    }
                    else
                    {
                        xj = lo [j] ;
                    }
                    x [j] = xj ;
                    b -= aj*xj ;
                    continue ;
                }
                else
                {
                    const NAPFLOAT t = aj*y [j] ;
                    num += t ;
                    const NAPFLOAT s = aj*aj ;
                    den += s ;
                    if ( k_gt_1 )
                    {
                        ada [j] = s ;
                        ady [j] = t ;
                    }
                }
            }
        }
        END_UNFIXED_LOOP ;

        /* Perform up to K iterations of the variable fixing algorithm
           treating the zero diagonal elements as vanishingly small numbers. */
        if ( den ) /* there exist some zero diagonal elements not at bounds */
        {
            status = NAPHEAP_STATUS_KEEP_LOOKING ; /* default status */
            for (it = 1; it <= K; it++)
            {
                lambda = num/den ;
                if ( lambda < lambdaL )
                {
                    lambda = lambdaL ;
                }
                else if ( lambda > lambdaR )
                {
                    lambda = lambdaR ;
                }
                /* slope corresponds to terms with no break point at lambda */
                slope = NAPZERO ;
                /* upper subdifferential terms associated with lambda */
                slopehi = NAPZERO ;
                /* lower subdifferential terms associated with lambda */
                slopelo = NAPZERO ;
                LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                    const NAPFLOAT aj = a [j] ;
                    if ( d [j] )
                    {
                        NAPFLOAT t = (y [j] - lambda*aj)/d [j] ;
                        if      ( loExists && (t < lo [j]) ) t = lo [j] ;
                        else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
                        slope += aj*t ;
                    }
                    else
                    {
                        NAPFLOAT t = breakpts [j] ;
                        /* update the slope of dual function */
                        if ( lambda < t )
                        {
                            if ( aj > NAPZERO ) slope += aj*hi [j] ;
                            else                slope += aj*lo [j] ;
                        }
                        else if ( lambda > t )
                        {
                            if ( aj > NAPZERO ) slope += aj*lo [j] ;
                            else                slope += aj*hi [j] ;
                        }
                        else /* lambda is a break point */
                        {
                            if ( aj > NAPZERO )
                            {
                                slopehi += aj*hi [j] ;
                                slopelo += aj*lo [j] ;
                            }
                            else
                            {
                                slopelo += aj*hi [j] ;
                                slopehi += aj*lo [j] ;
                            }
                        }
                    }
                END_LOOP
                slope -= b ;
                if ( slope + slopelo > NAPZERO )  /* optimal mult. is right */
                {
                    if ( lambdaL < lambda )
                    {
                        lambdaL = lambda ;
                        dL = slope + slopelo ;
                        Lout = FALSE ;
                    }
                    else lambda = lambdaL ;
                    if ( it == K ) break ;
                    LOOP_OVER_UNFIXED ;
                    {
                        if ( d [j] )
                        {
                            if ( br_hi [j] <= lambda ) /* fix xj */
                            {
                                NAPFLOAT xj ;
                                const NAPFLOAT aj = a [j] ;
                                if ( aj > NAPZERO ) xj = lo [j] ;
                                else                xj = hi [j] ;
                                b -= aj*xj ;
                                x [j] = xj ;
                                continue ;
                            }
                        }
                        else
                        {
                            if ( breakpts [j] < lambda ) /* xj is fixed */
                            {
                                NAPFLOAT xj ;
                                const NAPFLOAT aj = a [j] ;
                                if ( aj > NAPZERO ) xj = lo [j] ;
                                else                xj = hi [j] ;
                                b -= aj*xj ;
                                x [j] = xj ;
                                num -= ady [j] ;
                                den -= ada [j] ;
                                continue ;
                            }
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else if ( slope + slopehi < NAPZERO ) /* opt mult. is left */
                {
                    if ( lambdaR > lambda )
                    {
                        lambdaR = lambda ;
                        dR = slope + slopehi ;
                        Rout = FALSE ;
                    }
                    else lambda = lambdaR ;
                    if ( it == K ) break ;
                    LOOP_OVER_UNFIXED ;
                    {
                        if ( d [j] )
                        {
                            if ( br_lo [j] >= lambda ) /* fix xj */
                            {
                                NAPFLOAT xj ;
                                const NAPFLOAT aj = a [j] ;
                                if ( aj > NAPZERO ) xj = hi [j] ;
                                else                xj = lo [j] ;
                                b -= aj*xj ;
                                x [j] = xj ;
                                continue ;
                            }
                        }
                        else
                        {
                            if ( breakpts [j] > lambda ) /* xj is fixed */
                            {
                                NAPFLOAT xj ;
                                const NAPFLOAT aj = a [j] ;
                                if ( aj > NAPZERO ) xj = hi [j] ;
                                else                xj = lo [j] ;
                                b -= aj*xj ;
                                x [j] = xj ;
                                num -= ady [j] ;
                                den -= ada [j] ;
                                continue ;
                            }
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else /* optimal solution found */
                {
                    status = NAPHEAP_STATUS_OK ;
                    break ;
                }

                num -= b ;
                /* no variable fixed or all variables fixed */
                if ( (nuf == nk) || (nuf == 0) )
                {
                    /* solution not found since variable fixing only applied to
                       indices where dj = 0 */
                    break ;
                }
            }
            Stat->nvarfix = it ;
            if ( status == NAPHEAP_STATUS_OK )
            {
                napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                         loExists, hiExists, breakpts) ;
                napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                              free_heap, bound_heap, loExists, hiExists) ;
            }
        }
        else /* d is positive, variables for zero diagonal elements at bounds */
        {
            /* d is positive, no linear part */
            num = NAPZERO ;
            if ( K == 1 )
            {
                LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                    const NAPFLOAT aj = a [j] ;
                    NAPFLOAT t = aj/d [j] ;
                    num += t*y [j] ;
                    t *= aj ;
                    den += t ;
                END_LOOP ;
            }
            else
            {
                LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                    const NAPFLOAT aj = a [j] ;
                    NAPFLOAT t = aj/d [j] ;
                    NAPFLOAT s = t*y [j] ;
                    num += s ;
                    ady [j] = s ;
                    t *= aj ;
                    den += t ;
                    ada [j] = t ;
                END_LOOP
            }

            /* Perform up to K iterations of the variable fixing algorithm */
            status = NAPHEAP_STATUS_KEEP_LOOKING ; /* default status */
            for (it = 1; it <= K; it++)
            {
                /* evaluate new lambda and the slope */
                lambda  = (num-b)/den ;
                slope = NAPZERO ;
                LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                    const NAPFLOAT aj = a [j] ;
                    NAPFLOAT t = (y [j] - lambda*aj)/d [j] ;
                    if      ( loExists && (t < lo [j]) ) t = lo [j] ;
                    else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
                    slope += aj*t ;
                END_LOOP ;
                slope -= b ;

                if ( slope > NAPZERO )     /* optimal multiplier is to right */
                {
                    if ( lambdaL < lambda )
                    {
                        lambdaL = lambda ;
                        dL = slope ;
                    }
                    else
                    {
                        lambda = lambdaL ;
                        slope = dL ;
                    }
                    if ( it == K ) break ;
                    /* fix variables and compute next step */
                    LOOP_OVER_UNFIXED ;
                    {
                        if ( br_hi [j] <= lambda ) /* fix xj */
                        {
                            NAPFLOAT t ;
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            b -= aj*t ;
                            x [j] = t ;
                            num -= ady [j] ;
                            den -= ada [j] ;
                            continue ;
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else if ( slope < NAPZERO ) /* optimal multiplier is to left */
                {
                    if ( lambdaR > lambda )
                    {
                        lambdaR = lambda ;
                        dR = slope ;
                    }
                    else
                    {
                        lambda = lambdaR ;
                        slope = dR ;
                    }
                    if ( it == K ) break ;
                    /* fix variables and compute next step */
                    LOOP_OVER_UNFIXED ;
                    {
                        if ( br_lo [j] >= lambda ) /* fix xj */
                        {
                            NAPFLOAT t ;
                            const NAPFLOAT aj = a [j] ;
                            if ( aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            b -= aj*t ;
                            x [j] = t ;
                            num -= ady [j] ;
                            den -= ada [j] ;
                            continue ;
                        }
                    }
                    END_UNFIXED_LOOP ;
                }
                else /* optimal solution found (slope is zero) */
                {
                    status = NAPHEAP_STATUS_OK ;
                    break ;
                }

                /* no variables fixed or all variables fixed */
                if ( (nuf == nk) || (nuf == 0) )
                {
                    /* otherwise variable fixing, optimal solution found */
                    status = NAPHEAP_STATUS_OK ;
                    break ;
                }
            }

            Stat->nvarfix = it ;
            if ( status == NAPHEAP_STATUS_OK )
            {
                /* set unbound variables */
                 LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
                    const NAPFLOAT t = (y [j] - lambda*a [j])/d [j] ;
                    if ( loExists && (t < lo [j]) )
                    {
                        x [j] = lo [j] ;
                    }
                    else if ( hiExists && (t > hi [j]) )
                    {
                        x [j] = hi [j] ;
                    }
                    else
                    {
                        x [j] = t ;
                    }
                END_LOOP ;
            }
        }

        if ( status == NAPHEAP_STATUS_KEEP_LOOKING ) /* solution not found */
        {
            /* slope was computed in variable fixing algorithm */
            recompute_slope = FALSE ;
            status = NAPHEAP_STATUS_OK ;
            if ( dL < -dR ) /* go right */
            {
                lambda = lambdaL ;
                slope = dL ;
                goright = TRUE ;
                if ( Lout ) recompute_slope = TRUE ;
            }
            else /* go left unless lambdaR = INF */
            {
                if ( lambdaR < NAPINF )
                {
                    lambda = lambdaR ;
                    slope = dR ;
                    goright = FALSE ;
                    if ( Rout ) recompute_slope = TRUE ;
                }
                else
                {
                    lambda = lambdaL ;
                    slope = dL ;
                    goright = TRUE ;
                    if ( Lout ) recompute_slope = TRUE ;
                }
            }

            #ifdef NAPSACK_BRUTAL
            /* !!!!!!!!! mess up the slope for debugging !!!!!!!!!! */
            /* This is only for extensive debugging, not for production use. */
            if ( Parm->refine && n > 3 )
            {
                if ( slope > 0 )
                {
                    if ( a [3] > 0 ) slope += 5 ;
                    else             slope /= 4 ;
                }
                else
                {
                    if ( a [3] > 0 ) slope -= 5 ;
                    else             slope /= 4 ;
                }
            }
            #endif

            napsearch1 (x, &lambda, lambdaL, lambdaR, &b, &slope, &slopelo,
                        &slopehi, y, d, a, lo, hi, n, K, breakpts, uf, &nuf,
                        free_heap, bound_heap, goright, Stat, br_lo,
                        br_hi, recompute_slope, Parm, loExists, hiExists) ;

            /* fix all variables for which the break point != lambda */
            napfix1 (x, a, y, d, lo, hi, &b, lambda, uf, &nuf,
                     loExists, hiExists, breakpts) ;

            /* determine the variables for which di = 0 and the
               associated break point = lambda */
            napsolution0 (x, a, lo, hi, b, breakpts, uf, nuf,
                          free_heap, bound_heap, loExists, hiExists) ;
        }
    }

    /* wrapup and return solution */
    return (nap_wrapup (status, napdata, lambda)) ;
}

/* =========================================================================
 * ============================= napheap_setup =============================
 * ========================================================================= */
NAPdata * napheap_setup (void)
{
    int status ;
    NAPdata *Data ;
    status = NAPHEAP_STATUS_OK ;
    Data       = (NAPdata *) napheap_malloc (&status, 1, sizeof (NAPdata)) ;
    Data->Stat = (NAPstat *) napheap_malloc (&status, 1, sizeof (NAPstat)) ;
    Data->Parm = (NAPparm *) napheap_malloc (&status, 1, sizeof (NAPparm)) ;
    if ( status == NAPHEAP_STATUS_OUT_OF_MEMORY )
    {
        Data = NULL ;
        return (Data) ;
    }
    napheap_default (Data->Parm) ;

    /* A starting guess for x is not required.  If the user does not
       provide a pointer to x, then NAPHEAP allocates memory for the
       solution x. napheap_terminate will free any allocated memory.
       The x_created pointer is only used internally by NAPHEAP when
       it creates memory for x */
    Data->x         = NULL ;

    /* lambda, the multiplier associated with the constraint
       blo <= a'*x <= bhi, is initialized to +infinity. If the
       user gives a value to Data->lambda, then it is used as the
       starting guess for the multiplier. Otherwise, if Data->lambda
       remains +infinity, it is ignored. At the conclusion of the
       run, Data->lambda is the final multiplier associated with the
       linear constraint. */
    Data->lambda    = NAPINF ;

    Data->n         = EMPTY ;  /* problem dimension */
    Data->y         = NULL ;   /* linear term in the objective is -y'x */
    Data->d         = NULL ;   /* diagonal of objective Hessian */
    Data->a         = NULL ;   /* linear constraint vector */
    Data->blo       = -NAPINF; /* lower bound for a'x */
    Data->bhi       = NAPINF ; /* upper bound for a'x */
    Data->lo        = NULL ;   /* lower bound for x */
    Data->hi        = NULL ;   /* upper bound for x */
    Data->xWork     = NULL ;   /* NULL => let code allocate NAPFLOAT memory.
                                  Otherwise use xWork for NAPFLOAT memory.
                                  The amount of memory needed depends on the
                                  parameters in the Parm structure. See the
                                  memory allocation section of the code for the
                                  precise memory requirement (max size 5n). */
    Data->iWork     = NULL ;   /* NULL => let code allocate NAPINT memory.
                                  Otherwise use iWork for memory (4n+2) */

    /* the following are used internally when the code allocates memory */
    Data->x_created      = NULL ;
    Data->y_created      = NULL ;
    Data->xWork_created  = NULL ;
    Data->iWork_created  = NULL ;
    /* sum ak*ak/dk, k = 1:n, from a previous run */
    Data->akakdk         = NAPINF ;

    return (Data) ;
}

/* =========================================================================
 * ============================= napheap_terminate =========================
 * ========================================================================= */
void napheap_terminate
(
    NAPdata **DataHandle
)
{
    NAPdata *Data ;
    Data = *DataHandle ;
    if ( Data->x_created      != NULL ) napheap_free (Data->x_created) ;
    if ( Data->y_created      != NULL ) napheap_free (Data->y_created) ;
    if ( Data->xWork_created  != NULL ) napheap_free (Data->xWork_created) ;
    if ( Data->iWork_created  != NULL ) napheap_free (Data->iWork_created) ;
    napheap_free (Data->Stat) ;
    napheap_free (Data->Parm) ;
    napheap_free (Data) ;
}
/* ========================================================================== */
/* === napheap_malloc ======================================================= */
/* ========================================================================== */
void * napheap_malloc
(
    int *status,
    NAPINT    n,
    int    size
)
{
    void *p ;

    if ( n > 0 )
    {
#ifdef MATLAB_MEX_FILE
        p = mxMalloc (n*size) ;
#else
        p = malloc (n*size) ;
#endif
    }
    else
    {
        return (NULL) ;
    }

    if ( p == NULL )
    {
        *status = NAPHEAP_STATUS_OUT_OF_MEMORY ;
    }
    return (p) ;
}
/* ========================================================================== */
/* === napheap_free ========================================================= */
/* ========================================================================== */
void napheap_free
(
    void * p
)
{

#ifdef MATLAB_MEX_FILE
    mxFree (p) ;
#else
    free (p) ;
#endif

}

/* ========================================================================== */
/* === non-user-callable functions ========================================== */
/* ========================================================================== */

/* The remainder of the functions below are not user-callable. */

/* ========================================================================== */
/* === nap_wrapup =========================================================== */
/* ========================================================================== */

/* finalize the solution, free workspace, and return to the user */

PRIVATE int nap_wrapup
(
    int         status,
    NAPdata   *napdata,
    NAPFLOAT    lambda
)
{
    NAPparm *Parm ;
    Parm = napdata->Parm ;
    napdata->lambda = lambda ;
    napdata->Stat->status = status ;
    if ( Parm->PrintStatus == TRUE )
    {
        napheap_print_status (napdata) ;
    }
    if ( Parm->PrintStat )
    {
        napheap_print_stat (napdata) ;
    }

    if ( !Parm->return_data )
    {
        if ( napdata->y_created != NULL )
        {
            if ( napdata->y_created == napdata->y )
            {
                napheap_free (napdata->y_created) ;
                napdata->y_created = napdata->y = NULL ;
            }
            else
            {
                napheap_free (napdata->y_created) ;
                napdata->y_created = NULL ;
            }
        }
        if ( napdata->xWork_created != NULL )
        {
            if ( napdata->xWork_created == napdata->xWork )
            {
                napheap_free (napdata->xWork_created) ;
                napdata->xWork_created = napdata->xWork = NULL ;
            }
            else
            {
                napheap_free (napdata->xWork_created) ;
                napdata->xWork_created = NULL ;
            }
        }
        if ( napdata->iWork_created != NULL )
        {
            if ( napdata->iWork_created == napdata->iWork )
            {
                napheap_free (napdata->iWork_created) ;
                napdata->iWork_created = napdata->iWork = NULL ;
            }
            else
            {
                napheap_free (napdata->iWork_created) ;
                napdata->iWork_created = NULL ;
            }
        }
    }
    return (status) ;
}

/*  ==========================================================================
    === napsearch ============================================================
    ==========================================================================
    If the slope of the dual function at lambda is positive, then search
    over break points to the right. If the slope is negative, then search
    over break points to the left.
    ========================================================================= */

PRIVATE int napsearch   /* return status of solution process */
(
    NAPFLOAT        *x, /* size n. solution (output) */
    NAPFLOAT   *lambda, /* optimal multiplier (input = guess, output = sol)*/
    NAPFLOAT   lambdaL, /* optimal multiplier lies on [lambdaL, lambdaR] */
    NAPFLOAT   lambdaR, /* optimal multiplier lies on [lambdaL, lambdaR] */
    NAPFLOAT         B, /* a'x = B */
    NAPFLOAT     slope, /* derivative of dual function */
    NAPFLOAT const *ay, /* size n. linear term in objective function yj/aj */
    NAPFLOAT const *ad, /* size n, diagonal of objective Hessian aj/dj */
    NAPFLOAT const  *a, /* size n, linear constraint vector */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPINT   const   n, /* problem dimension */
    NAPFLOAT *breakpts, /* size n, breakpts [j] is br_hi[j] or br_lo[j] */
    NAPFLOAT *breaknext,/* size n, TRUE if 2 break points in search dir. */
    NAPINT         nuf, /* number of unfixed variables */
    NAPINT *known_free, /* location of first known free variable in uf */
    NAPINT     *n_free, /* number of indices in free heap */
    NAPINT    *n_bound, /* number of indices in bound heap */
    NAPINT         *uf, /* size n, list of unfixed variables */
    NAPINT         *kf, /* size n, list of known free variables */
    NAPINT  *free_heap, /* size n+1, heap of free variables */
    NAPINT *bound_heap, /* size n+1, heap of bound variables */
    NAPstat      *Stat, /* solution statistics */
    NAPparm      *Parm, /* parameters */
    int const loExists, /* TRUE when there are lower bound for x */
    int const hiExists  /* TRUE when there are upper bound for x */
)
{
    NAPINT   jb, jfree, k, nb, nf, nbound, nfree, nkf, nk ;
    NAPFLOAT b, maxbound, maxfree, minbound,
             minfree, new_break, a2sum, a2sum_free, a2max ;

    /* initialization */
    b = B ;
    a2sum = NAPZERO ;      /* sum aj*aj/dj for all free variables */
    a2sum_free = NAPZERO ; /* sum aj*aj/dj for all known free variables */
    nbound = 0 ;           /* current number of bound variables */
    nfree = 0 ;            /* current number of free variables */
    nb = n ;               /* pointer to start of previously bound variables */
    nf = n ;               /* pointer to start of previously free variables */
    nkf = 0 ;              /* number of known free variables */
    const int d_is_one = Parm->d_is_one ; /* TRUE if d = 1 */
    if ( slope > NAPZERO ) /* move right */
    {
        /* d is positive and lambda is to the left of the true multiplier.
           Get ready to search over the break points to the right by
           constructing the heaps for currently bound and free variables,
           and by fixing variables whose break points are to the left.
           If the current iterate crossed the root, can exploit this in
           freeing variables. */
        LOOP_OVER_UNFIXED ;
        {
            const NAPFLOAT aj = a [j] ;
            if ( aj > NAPZERO )
            {
                const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                if ( loExists && (x [j] == loj) )
                {
                    b -= aj*loj ; /* fix j */
                    continue ;
                }
                else /* either 0 or 1 or 2 break points ahead */
                {
                    const NAPFLOAT ayj = ay [j] ;
                    const NAPFLOAT adj = (d_is_one) ? aj : ad [j] ;
                    if ( hiExists )
                    {
                        const NAPFLOAT s = ayj - hi [j]/adj ; /*lo break point*/
                        if ( *lambda < s )            /* 2 break points ahead */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = s ;
                            if ( loj > -NAPINF )
                            {
                                const NAPFLOAT r = ayj - loj/adj ; /*next brk */
                                if ( r < lambdaR )
                                {
                                    breaknext [j] = r ; /* next break */
                                }
                                else
                                {
                                    breaknext [j] = NAPINF ; /*no more brk pts*/
                                }
                            }
                            else
                            {
                                breaknext [j] = NAPINF ; /* no more brk pts */
                            }
                        }
                        else /* 0 or 1 break points ahead */
                        {
                            const NAPFLOAT r = ayj - loj/adj ; /* hi brk point*/
                            if ( r >= lambdaR )            /* j is known free */
                            {
                                a2sum_free += aj*adj ;
                                kf [nkf] = j ;
                                nkf++ ;
                                continue ;
                            }
                            else /* j free, exactly 1 break point ahead */
                            {
                                a2sum += aj*adj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = r ;
                                breaknext [j] = NAPINF ; /* no more break pts */
                            }
                        }
                    }
                    else
                    {
                        const NAPFLOAT r = ayj - loj/adj ; /* hi brk point*/
                        if ( r >= lambdaR )                /* j is known free */
                        {
                            a2sum_free += aj*adj ;
                            kf [nkf] = j ;
                            nkf++ ;
                            continue ;
                        }
                        else /* j free, exactly 1 break point ahead */
                        {
                            a2sum += aj*adj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = r ;
                            breaknext [j] = NAPINF ; /* no more break pts */
                        }
                    }
                }
            }
            else /* aj < 0 */
            {
                const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                if ( hiExists && (x [j] == hij) )
                {
                    b -= aj*hij ; /* fix j */
                    continue ;
                }
                else /* either 0 or 1 or 2 break points ahead */
                {
                    const NAPFLOAT ayj = ay [j] ;
                    const NAPFLOAT adj = (d_is_one) ? aj : ad [j] ;
                    if ( loExists )
                    {
                        const NAPFLOAT s = ayj - lo [j]/adj ; /* lo break pt */
                        if ( *lambda < s )           /* 2 break points ahead */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = s ;
                            if ( hij < NAPINF )
                            {
                                const NAPFLOAT r =  ayj - hij/adj ; /*next brk*/
                                if ( r < lambdaR )
                                {
                                    breaknext [j] = r ; /* next break */
                                }
                                else
                                {
                                    breaknext [j] = NAPINF ; /*no more brk pts*/
                                }
                            }
                            else
                            {
                                breaknext [j] = NAPINF ; /* no more brk pts */
                            }
                        }
                        else /* 0 or 1 break points ahead */
                        {
                            const NAPFLOAT r = ayj - hij/adj ; /* hi break pt*/
                            if ( r >= lambdaR ) /* j is known free */
                            {
                                a2sum_free += aj*adj ;
                                kf [nkf] = j ;
                                nkf++ ;
                                continue ;
                            }
                            else /* j free, exactly 1 break point ahead */
                            {
                                a2sum += aj*adj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = r ;
                                breaknext [j] = NAPINF ; /* no more break pts */
                            }
                        }
                    }
                    else /* 0 or 1 break points ahead */
                    {
                        const NAPFLOAT r = ayj - hij/adj ; /* hi break pt*/
                        if ( r >= lambdaR ) /* j is known free */
                        {
                            a2sum_free += aj*adj ;
                            kf [nkf] = j ;
                            nkf++ ;
                            continue ;
                        }
                        else /* j free, exactly 1 break point ahead */
                        {
                            a2sum += aj*adj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = r ;
                            breaknext [j] = NAPINF ; /* no more break pts */
                        }
                    }
                }
            }
        }
        END_UNFIXED_LOOP ;
        if ( (nuf == 0) && (nkf == 0) ) /* all variables bounds */
        {
            return (NAPHEAP_STATUS_INFEASIBLE) ;
        }

       /* recompute a2sum when it becomes much smaller than its max */
        a2sum += a2sum_free ;
        a2max = a2sum ;

        /* build heap for free variables */
        Stat->nfree = nfree ;
        napminheap_build (free_heap, breakpts, nfree) ;

        /* build heap for bound variables */
        Stat->nbound = nbound ;
        napminheap_build (bound_heap, breakpts, nbound) ;

        /* d is positive, lambda is to the left of the true multiplier, and
           the break points are stored in a heap.  Search over the break points
           to the right until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            minfree = breakpts [jfree] ;
        }
        else minfree = NAPINF ;

        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            minbound = breakpts [jb] ;
        }
        else minbound = NAPINF ;

        while ( 1 )
        {
            new_break = MIN (minfree, minbound) ;
            const NAPFLOAT t = slope - a2sum*(new_break - *lambda) ;
            if ( (t <= NAPZERO) || (new_break >= NAPINF) ) /* done */
            {
                Stat->nbrks = (n-nf) + (n-nb) ;

                /* Final update when there are free variables */
                if ( (nfree > 0) || (nkf > 0) )
                {
                    *lambda += slope/a2sum ;
                    break ;
                }
                else if ( slope > NAPZERO ) /* Problem infeasible */
                {
                    return (NAPHEAP_STATUS_INFEASIBLE) ;
                }
            }
            *lambda = new_break ;
            slope = t ;

            /* update the heaps */
            while ( *lambda == minfree )
            {
                /* delete break point from heap */
                nfree = napminheap_delete (free_heap, breakpts, nfree) ;

                /* add break point to list of previously free variables */
                free_heap [nf] = jfree ;
                nf-- ;

                /* update a2sum */
                const NAPFLOAT aj = a [jfree] ;
                a2sum -= (d_is_one) ? aj*aj : aj*ad [jfree] ;

                /* store x [jfree], it must be bound */
                if ( aj > 0 ) x [jfree] = lo [jfree] ;
                else          x [jfree] = hi [jfree] ;

                /* recompute a2sum if it has significant decay */
                if ( a2sum < Parm->decay*a2max )
                {
                    a2sum = a2sum_free ;
                    for (k = 1; k <= nfree; k++)
                    {
                        const NAPINT j = free_heap [k] ;
                        a2sum += (d_is_one) ? a [j]*a [j] : a [j]*ad [j] ;
                    }
                    a2max = a2sum ;
                }

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    minfree = NAPINF ;
                    break ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;
                }
            }

            while ( *lambda == minbound )
            {
                /* delete break point from heap */
                nbound  = napminheap_delete(bound_heap, breakpts, nbound);

                /* add break point to list of previously bound  variables */
                bound_heap [nb] = jb ;
                nb-- ;

                /* compute new hi break point if necessary */
                const NAPFLOAT s = breaknext [jb] ;
                if ( s < NAPINF )
                {
                    breakpts [jb] = s ;

                    /* add new break point to free heap */
                    nfree = napminheap_add (free_heap, breakpts, jb, nfree);

                    /* get the smallest entry in free heap */
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;
                    a2sum += d_is_one ? a [jb]*a [jb] : a [jb]*ad [jb] ;
                }
                else /* variable is known free */
                {
                    const NAPFLOAT r = (d_is_one) ? a [jb]*a [jb] :
                                                    a [jb]*ad [jb] ;
                    a2sum_free += r ;
                    a2sum += r ;
                    kf [nkf] = jb ;
                    nkf++ ;
                }

                if ( a2sum > a2max )
                {
                    a2max = a2sum ;
                }

                /* get the smallest entry in bound heap */
                if ( nbound == 0 ) minbound = NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    minbound = breakpts [jb] ;
                }
            }
        }
    }
    else if ( slope < NAPZERO ) /* move left */
    {
        /* d is positive and lambda is to the right of the true multiplier.
           Get ready to search over the break points to the left by
           constructing the heaps for currently bound and free variables,
           and by fixing variables whose break points are to the right.
           If the current iterate crossed the root, can exploit this to
           free variables. */
        LOOP_OVER_UNFIXED ;
        {
            const NAPFLOAT aj = a [j] ;
            if ( aj > NAPZERO )
            {
                const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                if ( hiExists && (x [j] == hij) )
                {
                    b -= aj*hij ; /* fix j */
                    continue ;
                }
                else /* either 0 or 1 or 2 break points ahead */
                {
                    const NAPFLOAT ayj = ay [j] ;
                    const NAPFLOAT adj = (d_is_one) ? aj : ad [j] ;
                    if ( loExists )
                    {
                        const NAPFLOAT s = ayj - lo [j]/adj ; /* hi brk point */
                        if ( *lambda > s )        /* 2 break points ahead */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = s ;
                            if ( hij < NAPINF )
                            {
                                const NAPFLOAT r = ayj - hij/adj ;/*next brk */
                                if ( r > lambdaL )
                                {
                                        breaknext [j] = r ; /* next break */
                                }
                                else
                                {
                                    breaknext [j] = NAPINF ; /*no more brk pts*/
                                }
                            }
                            else
                            {
                                breaknext [j] = NAPINF ; /* no more brk pts */
                            }
                        }
                        else /* 0 or 1 break points ahead */
                        {
                            const NAPFLOAT r = ayj - hij/adj ; /* lo brk point*/
                            if ( r <= lambdaL ) /* j is known free */
                            {
                                a2sum_free += aj*adj ;
                                kf [nkf] = j ;
                                nkf++ ;
                                continue ;
                            }
                            else /* j free, exactly 1 break point ahead */
                            {
                                a2sum += aj*adj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = r ;
                                breaknext [j] = NAPINF ; /* no more break pts */
                            }
                        }
                    }
                    else /* 0 or 1 break points ahead */
                    {
                        const NAPFLOAT r = ayj - hij/adj ; /* lo break point*/
                        if ( r <= lambdaL ) /* j is known free */
                        {
                            a2sum_free += aj*adj ;
                            kf [nkf] = j ;
                            nkf++ ;
                            continue ;
                        }
                        else /* j free, exactly 1 break point ahead */
                        {
                            a2sum += aj*adj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = r ;
                            breaknext [j] = NAPINF ; /* no more break pts */
                        }
                    }
                }
            }
            else /* aj < 0 */
            {
                const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                if ( loExists && (x [j] == loj) )
                {
                    b -= aj*loj ; /* fix j */
                    continue ;
                }
                else /* either 0 or 1 or 2 break points ahead */
                {
                    const NAPFLOAT ayj = ay [j] ;
                    const NAPFLOAT adj = (d_is_one) ? aj : ad [j] ;
                    if ( hiExists )
                    {
                        const NAPFLOAT s = ayj - hi [j]/adj ; /* hi brk point */
                        if ( *lambda > s )        /* 2 break points ahead */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = s ;
                            if ( loj > -NAPINF )
                            {
                                const NAPFLOAT r = ayj - loj/adj ; /*next brk*/
                                if ( r > lambdaL )
                                {
                                    breaknext [j] = r ; /* next break */
                                }
                                else
                                {
                                    breaknext [j] = NAPINF ; /*no more brk pts*/
                                }
                            }
                            else
                            {
                                breaknext [j] = NAPINF ; /* no more brk pts */
                            }
                        }
                        else /* 0 or 1 break points ahead */
                        {
                            const NAPFLOAT r = ayj - loj/adj ; /* lo break pt*/
                            if ( r <= lambdaL ) /* j is known free */
                            {
                                a2sum_free += aj*adj ;
                                kf [nkf] = j ;
                                nkf++ ;
                                continue ;
                            }
                            else /* j free, exactly 1 break point ahead */
                            {
                                a2sum += aj*adj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = r ;
                                breaknext [j] = NAPINF ; /* no more break pts */
                            }
                        }
                    }
                    else /* 0 or 1 break points ahead */
                    {
                        const NAPFLOAT r = ayj - loj/adj ; /* lo break pt*/
                        if ( r <= lambdaL ) /* j is known free */
                        {
                            a2sum_free += aj*adj ;
                            kf [nkf] = j ;
                            nkf++ ;
                            continue ;
                        }
                        else /* j free, exactly 1 break point ahead */
                        {
                            a2sum += aj*adj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = r ;
                            breaknext [j] = NAPINF ; /* no more break pts */
                        }
                    }
                }
            }
        }
        END_UNFIXED_LOOP ;
        if ( (nuf == 0) && (nkf == 0) ) /* all variables at bounds */
        {
            return (NAPHEAP_STATUS_INFEASIBLE) ;
        }

       /* recompute a2sum when it becomes much smaller than its max */
        a2sum += a2sum_free ;
        a2max = a2sum ;

        /* build the free heap */
        Stat->nfree = nfree ;
        napmaxheap_build (free_heap, breakpts, nfree) ;

        /* build the bound heap */
        Stat->nbound = nbound ;
        napmaxheap_build (bound_heap, breakpts, nbound) ;

        /* d is positive, lambda is to the right of the true multiplier, and
           the break points are stored in a heap.  Search over the break points
           to the left until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            maxfree = breakpts [jfree] ;
        }
        else maxfree = -NAPINF ;

        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            maxbound = breakpts [jb] ;
        }
        else maxbound = -NAPINF ;

        while ( 1 )
        {
            new_break = MAX (maxfree, maxbound) ;
            const NAPFLOAT t = slope - a2sum*(new_break - *lambda) ;
            if ( (t >= NAPZERO) || (new_break <= -NAPINF) ) /* done */
            {
                Stat->nbrks = (n-nb) + (n-nf) ;

                /* Final update when there are free variables */
                if ( ((nfree > 0) || (nkf > 0)) && (a2sum > NAPZERO) )
                {
                    *lambda += slope/a2sum ;
                    break ;
                }
                else if ( slope < NAPZERO ) /* problem is infeasible */
                {
                    return (NAPHEAP_STATUS_INFEASIBLE) ;
                }
            }
            *lambda = new_break ;
            slope = t ;

            /* update the heaps */
            while ( *lambda == maxfree )
            {
                /* delete break point from heap */
                nfree = napmaxheap_delete (free_heap, breakpts, nfree) ;

                /* add break point to list of previously free variables */
                free_heap [nf] = jfree ;
                nf-- ;

                /* update a2sum */
                const NAPFLOAT aj = a [jfree] ;
                a2sum -= (d_is_one) ? aj*aj : aj*ad [jfree] ;

                /* recompute a2sum if it has significant decay */
                if ( a2sum < Parm->decay*a2max )
                {
                    a2sum = a2sum_free ;
                    for (k = 1; k <= nfree; k++)
                    {
                        const NAPINT j = free_heap [k] ;
                        a2sum += (d_is_one) ? a [j]*a [j] : a [j]*ad [j] ;
                    }
                    a2max = a2sum ;
                }

                /* store x [jfree] */
                if ( aj > 0 ) x [jfree] = hi [jfree] ;
                else          x [jfree] = lo [jfree] ;

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    maxfree = -NAPINF ;
                    break ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;
                }
            }
            while ( *lambda == maxbound )
            {
                /* delete break point from heap */
                nbound  = napmaxheap_delete(bound_heap, breakpts, nbound);

                /* add break point to list of previously bound variables */
                bound_heap [nb] = jb ;
                nb-- ;

                /* compute new lo break point if necessary */
                const NAPFLOAT s = breaknext [jb] ;
                if ( s < NAPINF )
                {
                    breakpts [jb] = s ;

                    /* add new break point to free heap */
                    nfree = napmaxheap_add (free_heap, breakpts, jb, nfree);

                    /* get the smallest entry in free heap */
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;
                    a2sum += (d_is_one) ? a [jb]*a [jb] : a [jb]*ad [jb] ;
                }
                else /* variable is known free */
                {
                    const NAPFLOAT r = (d_is_one) ? a [jb]*a [jb] :
                                                    a [jb]*ad [jb] ;
                    a2sum_free += r ;
                    a2sum += r ;
                    kf [nkf] = jb ;
                    nkf++ ;
                }

                if ( a2sum > a2max )
                {
                    a2max = a2sum ;
                }

                /* get the largest entry in bound heap */
                if ( nbound == 0 ) maxbound = -NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    maxbound = breakpts [jb] ;
                }
            }
        }
    }

    *n_free  = nfree;
    *n_bound = nbound;
    *known_free = nkf ;
    return (NAPHEAP_STATUS_OK) ;
}

/*  =========================================================================
    === napsearch0 ==========================================================
    =========================================================================
    If the slope of the dual function at lambda is positive,
    then search over break points to the right. If the slope is negative,
    then search over break points to the left. Recompute the slope at the
    current lambda and possibly refine x. It is assumed that d is zero.
    =========================================================================*/

PRIVATE void napsearch0
(
    NAPFLOAT              *x, /* size n. solution (output) */
    NAPFLOAT         *lambda, /* optimal multiplier (in = guess, out = sol) */
    NAPFLOAT         lambdaL, /* optimal multiplier lies on [lambdaL, lambdaR]*/
    NAPFLOAT         lambdaR, /* optimal multiplier lies on [lambdaL, lambdaR]*/
    NAPFLOAT              *b, /* a'x = b */
    NAPFLOAT          *slope, /* slope (exclude break point term) */
    NAPFLOAT        *slopelo, /* lower subdifferential associated with break */
    NAPFLOAT        *slopehi, /* upper subdifferential associated with break */
    NAPINT   const         n, /* problem dimension */
    NAPFLOAT const        *a, /* size n, linear constraint vector */
    NAPFLOAT const       *lo, /* size n, lower bounds on x */
    NAPFLOAT const       *hi, /* size n, upper bounds on x */
    NAPFLOAT const *breakpts, /* size n, breakpts [j] is br_hi[j] or br_lo[j] */
    NAPINT               *uf, /* size n, list of unfixed variables */
    NAPINT         *nunfixed, /* number of unfixed variables */
    NAPINT       *bound_heap, /* size n+1, heap of bound variables */
    int              goright, /* if true, move right, else move left */
    NAPstat            *Stat, /* solution statistics */
    int      recompute_slope, /* if true, then recompute slope */
    NAPparm            *Parm, /* parameters */
    int      const  loExists, /* TRUE when there are lower bound for x */
    int      const  hiExists  /* TRUE when there are upper bound for x */
)
{
    int refine ;
    NAPINT k, Nb, nb, nbound, nuf, nk ;
    NAPFLOAT t, err ;
    const int lohiExist = (loExists && hiExists) ;

    /* initialization */
    err = Parm->err ; /* error threshhold that triggers refinement */
    refine = Parm->refine ; /* TRUE means to refine the solution */
    nuf = *nunfixed ;
    nb = n ;       /* pointer to start of previously bound variables */
    nbound = 0 ;   /* number of break points */

    if ( goright ) /* move right */
    {
        /* d is zero and lambda is to the left of the true multiplier.
           Get ready to search over the break points to the right by
           constructing the heaps for currently bound,
           and by fixing variables whose break points are to the left.
           Moreover, if the slope at lambda is not known, then compute it. */
        if ( recompute_slope )
        {
            *slope = NAPZERO ;
            *slopehi = NAPZERO ;
            *slopelo = NAPZERO ;
            LOOP_OVER_UNFIXED ;
            {
                const NAPFLOAT aj = a [j] ;
                t = breakpts [j] ;
                if ( t < *lambda )
                {
                    if ( aj > NAPZERO ) t = lo [j] ;
                    else                t = hi [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                else if ( t > lambdaR )
                {
                    if ( aj > NAPZERO ) t = hi [j] ;
                    else                t = lo [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                else
                {
                    if ( t > *lambda )
                    {
                        nbound++ ;
                        bound_heap [nbound] = j ;
                        if ( aj > NAPZERO ) *slope += aj*hi [j] ;
                        else                *slope += aj*lo [j] ;
                    }
                    else /* lambda = break point */
                    {
                        if ( aj > NAPZERO )
                        {
                            *slopehi = (hiExists) ?
                                     *slopehi + aj*hi [j] :  NAPINF ;
                            *slopelo = (loExists) ?
                                     *slopelo + aj*lo [j] : -NAPINF ;
                        }
                        else
                        {
                            *slopelo = (loExists) ?
                                     *slopelo + aj*hi [j] : -NAPINF ;
                            *slopehi = (hiExists) ?
                                     *slopehi + aj*lo [j] :  NAPINF ;
                        }
                    }
                }
            }
            END_UNFIXED_LOOP ;
            *slope -= *b ;
            if ( *slope + *slopelo <= NAPZERO ) /* lambda is optimal */
            {
                *nunfixed = nuf ;
                return ;
            }
            *slope += *slopelo ;
        }
        else /* no need to compute slope, focus on heaps */
        {
            LOOP_OVER_UNFIXED ;
            {
                t = breakpts [j] ;
                if ( t <= *lambda )
                {
                    const NAPFLOAT aj = a [j] ;
                    if ( aj > NAPZERO ) t = lo [j] ;
                    else                t = hi [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                else if ( t > lambdaR )
                {
                    const NAPFLOAT aj = a [j] ;
                    if ( aj > NAPZERO ) t = hi [j] ;
                    else                t = lo [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                nbound++ ;
                bound_heap [nbound] = j ;
            }
            END_UNFIXED_LOOP ;
        }

        /* build the bound heap */
        Stat->nbound = nbound ;
        napminheap_build (bound_heap, breakpts, nbound) ;

        if ( nbound == 0 ) /* we cannot make the slope any smaller */
        {
            Stat->nbrks = n - nb ;
            *nunfixed = nuf ;
            return ;
        }
        /* d is zero, lambda is to the left of the true multiplier, and
           the break points are stored in a heap.  Search over the break
           points to the right until finding 0 slope */
        while ( *lambda == breakpts [bound_heap [1]] ) /* skip over lambda */
        {
            nbound = napminheap_delete (bound_heap, breakpts, nbound) ;
            if ( nbound == 0 ) break ;
        }
        if ( lohiExist )
        {
            while ( nbound > 0 )
            {
                const NAPINT j = bound_heap [1] ;
                *lambda = breakpts [j] ;
                t = *slope - fabs (a [j])*(hi [j] - lo [j]) ;
                if ( t <= NAPZERO )
                {
                    break ; /* done */
                }
                *slope = t ;

                /* delete break point from heap */
                nbound = napminheap_delete (bound_heap, breakpts, nbound) ;

                /* save break point for potential later refinement */
                bound_heap [nb] = j ;
                nb-- ;
            }
        }
        else
        {
            if ( nbound ) *lambda = breakpts [bound_heap [1]] ;
        }
    }
    else
    {
        /* d is zero and lambda is to the left of the true multiplier.
           Get ready to search over the break points to the right by
           constructing the heaps for currently bound,
           and by fixing variables whose break points are to the left.
           Moreover, if the slope at lambda is not known, then compute it. */
        if ( recompute_slope )
        {
            *slope = NAPZERO ;
            *slopehi = NAPZERO ;
            *slopelo = NAPZERO ;
            LOOP_OVER_UNFIXED ;
            {
                const NAPFLOAT aj = a [j] ;
                t = breakpts [j] ;
                if ( t > *lambda )
                {
                    if ( aj > NAPZERO ) t = hi [j] ;
                    else                t = lo [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                else if ( t < lambdaL )
                {
                    if ( aj > NAPZERO ) t = lo [j] ;
                    else                t = hi [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                if ( t < *lambda )
                {
                    nbound++ ;
                    bound_heap [nbound] = j ;
                    if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                    else                *slope += aj*hi [j] ;
                }
                else /* lambda = break point */
                {
                    if ( aj > NAPZERO )
                    {
                        *slopehi = (hiExists) ?
                                 *slopehi + aj*hi [j] :  NAPINF ;
                        *slopelo = (loExists) ?
                                 *slopelo + aj*lo [j] : -NAPINF ;
                    }
                    else
                    {
                        *slopelo = (loExists) ?
                                 *slopelo + aj*hi [j] : -NAPINF ;
                        *slopehi = (hiExists) ?
                                 *slopehi + aj*lo [j] :  NAPINF ;
                    }
                }
            }
            END_UNFIXED_LOOP ;
            *slope -= *b ;
            if ( *slope + *slopehi >= NAPZERO ) /* lambda is optimal */
            {
                *nunfixed = nuf ;
                return ;
            }
            *slope += *slopehi ;
        }
        else /* no need to compute slope, focus on heaps */
        {
            LOOP_OVER_UNFIXED ;
            {
                t = breakpts [j] ;
                if ( t >= *lambda )
                {
                    const NAPFLOAT aj = a [j] ;
                    if ( aj > NAPZERO ) t = hi [j] ;
                    else                t = lo [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                else if ( t < lambdaL )
                {
                    const NAPFLOAT aj = a [j] ;
                    if ( aj > NAPZERO ) t = lo [j] ;
                    else                t = hi [j] ;
                    *b -= aj*t ;
                    x [j] = t ;
                    continue ;
                }
                nbound++ ;
                bound_heap [nbound] = j ;
            }
            END_UNFIXED_LOOP ;
        }


        /* build the bound heap */
        Stat->nbound = nbound ;
        napmaxheap_build (bound_heap, breakpts, nbound) ;

        /* d is zero, lambda is to the right of the true multiplier, and
           the break points are stored in a heap.  Search over the break points
           to the left until finding 0 slope */
        if ( nbound == 0 ) /* we cannot make the slope any smaller */
        {
            Stat->nbrks = n - nb ;
            *nunfixed = nuf ;
            return ;
        }
        /* skip over breakpoints = lambda */
        while ( *lambda == breakpts [bound_heap [1]] )
        {
            nbound = napmaxheap_delete (bound_heap, breakpts, nbound) ;
            if ( nbound == 0 ) break ;
        }
        if ( lohiExist )
        {
            while ( nbound )
            {
                const NAPINT j = bound_heap [1] ;
                *lambda = breakpts [j] ;
                t = *slope + fabs (a [j])*(hi [j] - lo [j]) ;
                if ( t >= NAPZERO )
                {
                    break ;
                }
                *slope = t ;

                /* delete break point from heap */
                nbound = napmaxheap_delete (bound_heap, breakpts, nbound) ;

                /* save break point for potential later refinement */
                bound_heap [nb] = j ;
                nb-- ;
            }
        }
        else
        {
            if ( nbound ) *lambda = breakpts [bound_heap [1]] ;
        }
    }
    Stat->nbrks = n - nb ;

    if ( refine )
    {
        /* evaluate slope at lambda */
        *slopehi  = NAPZERO ; /* upper bound on slope at given lambda */
        *slopelo  = NAPZERO ; /* lower bound on slope at given lambda */
        *slope = NAPZERO ;    /* slope ignoring any break point at lambda */

        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            const NAPFLOAT aj = a [j] ;
            t = breakpts [j] ;
            /* update the slope of dual function */
            if ( *lambda < t )
            {
                if ( aj > NAPZERO ) *slope += aj*hi [j] ;
                else                *slope += aj*lo [j] ;
            }
            else if ( *lambda > t )
            {
                if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                else                *slope += aj*hi [j] ;
            }
            else /* lambda is a break point */
            {
                if ( aj > NAPZERO )
                {
                    *slopehi = (hiExists) ?
                             *slopehi + aj*hi [j] :  NAPINF ;
                    *slopelo = (loExists) ?
                             *slopelo + aj*lo [j] : -NAPINF ;
                }
                else
                {
                    *slopelo = (loExists) ?
                             *slopelo + aj*hi [j] : -NAPINF ;
                    *slopehi = (hiExists) ?
                             *slopehi + aj*lo [j] :  NAPINF ;
                }
            }
        END_LOOP ;
        *slope -= *b ;

        /* check if lambda is optimal */
        if ( (*slope+*slopelo <= NAPZERO) && (*slope+*slopehi >= NAPZERO) )
        {
            *nunfixed = nuf ;
            return ;
        }

        /* refine lambda */
        Nb = nb ;

        if ( goright )
        {
            if ( *slope + *slopelo >  err )
            {
                *slope += *slopelo ;
                if ( nbound == 0 ) /* we cannot make the slope any smaller */
                {
                    Stat->nbrks = n - nb ;
                    *nunfixed = nuf ;
                    return ;
                }
                /* d is zero, lambda is to the left of the true multiplier, and
                   the break points are stored in a heap.  Search over the break
                   points to the right until finding 0 slope. Skip over the
                   break points equal to lambda */
                while ( *lambda == breakpts [bound_heap [1]] )
                {
                    nbound = napminheap_delete (bound_heap, breakpts, nbound) ;
                    if ( nbound == 0 ) break ;
                }
                if ( lohiExist )
                {
                    while ( nbound > 0 )
                    {
                        const NAPINT j = bound_heap [1] ;
                        *lambda = breakpts [j] ;
                        t = *slope - fabs (a [j])*(hi [j] - lo [j]) ;
                        if ( t <= NAPZERO )
                        {
                            break ; /* done */
                        }
                        *slope = t ;

                        /* delete break point from heap */
                        nbound = napminheap_delete (bound_heap,breakpts,nbound);

                        /* save break point for potential later refinement */
                        bound_heap [nb] = j ;
                        nb-- ;
                    }
                }
                else
                {
                    if ( nbound ) *lambda = breakpts [bound_heap [1]] ;
                }
                Stat->nrefine = Nb - nb ;
            }
            else if ( *slope + *slopehi < -err )
            {
                for (nb++; nb <= n; nb++)
                {
                    const NAPINT j = bound_heap [nb] ;
                    if ( *lambda > breakpts [j] )
                    {
                        break ;
                    }
                }
                *slope += *slopehi ;
                if ( lohiExist )
                {
                    for (; nb <= n; nb++)
                    {
                        const NAPINT j = bound_heap [nb] ;
                        t = *slope + fabs (a [j])*(hi [j] - lo [j]) ;
                        if ( t >= NAPZERO )
                        {
                            *lambda = breakpts [j] ;
                            break ;
                        }
                        *slope = t ;
                    }
                }
                else
                {
                    if ( nb <= n ) *lambda = breakpts [bound_heap [nb]] ;
                }
                /* with exact arithmetic, terminate inside the loop above */
                Stat->nrefine = nb - Nb ;
            }
        }
        else /* go left */
        {
            if ( *slope + *slopehi < -err ) /* continue going left */
            {
                *slope += *slopehi ;
                /* d is zero, lambda is to the right of the true multiplier, and
                   the break points are stored in a heap.  Search over the break
                   points to the left until finding 0 slope */
                if ( nbound == 0 ) /* we cannot make the slope any smaller */
                {
                    Stat->nbrks = n - nb ;
                    *nunfixed = nuf ;
                    return ;
                }
                /* skip over breakpoints = lambda */
                while ( *lambda == breakpts [bound_heap [1]] )
                {
                    nbound = napmaxheap_delete (bound_heap, breakpts, nbound) ;
                    if ( nbound == 0 ) break ;
                }
                if ( lohiExist )
                {
                    while ( nbound )
                    {
                        const NAPINT j = bound_heap [1] ;
                        *lambda = breakpts [j] ;
                        t = *slope + fabs (a [j])*(hi [j] - lo [j]) ;
                        if ( t >= NAPZERO )
                        {
                            break ;
                        }
                        *slope = t ;

                        /* delete break point from heap */
                        nbound = napmaxheap_delete (bound_heap,breakpts,nbound);

                        /* save break point for potential later refinement */
                        bound_heap [nb] = j ;
                        nb-- ;
                    }
                }
                else
                {
                    if ( nbound ) *lambda = breakpts [bound_heap [1]] ;
                }
                Stat->nrefine = Nb - nb ;
            }
            else if ( *slope + *slopelo >  err ) /* switch to right */
            {
                *slope += *slopelo ;
                for (nb++; nb <= n; nb++)
                {
                    NAPINT j = bound_heap [nb] ;
                    if ( *lambda < breakpts [j] )
                    {
                        break ;
                    }
                }
                if ( lohiExist )
                {
                    for (; nb <= n; nb++)
                    {
                        const NAPINT j = bound_heap [nb] ;
                        t = *slope - fabs (a [j])*(hi [j] - lo [j]) ;
                        if ( t <= NAPZERO )
                        {
                            *lambda = breakpts [j] ;
                            break ;
                        }
                        *slope = t ;
                    }
                }
                else
                {
                    if ( nb <= n ) *lambda = breakpts [bound_heap [nb]] ;
                }
                /* with exact arithmetic, terminate inside the loop above */
                Stat->nrefine = nb - Nb ;
            }
        }
    }
    *nunfixed = nuf ;
}

/*  =========================================================================
    === napsearch1 ==========================================================
    =========================================================================
    If the slope of the dual function at lambda is positive,
    then search over break points to the right. If the slope is negative,
    then search over break points to the left. Recompute the slope at the
    current lambda and possibly refine x. It is assumed that d is neither
    identically 0 nor identically positive.
    =========================================================================*/

PRIVATE void napsearch1
(
    NAPFLOAT           *x,/* size n. solution (output) */
    NAPFLOAT      *lambda,/* optimal multiplier (input = guess, output = sol) */
    NAPFLOAT      lambdaL,/* optimal multiplier lies on [lambdaL, lambdaR] */
    NAPFLOAT      lambdaR,/* optimal multiplier lies on [lambdaL, lambdaR] */
    NAPFLOAT           *b,/* a'x = b */
    NAPFLOAT       *slope,/*  slope excluding term associated with break point*/
    NAPFLOAT     *slopelo,/* lower subdifferential associated with break point*/
    NAPFLOAT     *slopehi,/* upper subdifferential associated with break point*/
    NAPFLOAT const     *y,/* size n. linear term in objective function */
    NAPFLOAT const     *d,/* size n, diagonal of objective Hessian */
    NAPFLOAT const     *a,/* size n, linear constraint vector */
    NAPFLOAT const    *lo,/* size n, lower bounds on x */
    NAPFLOAT const    *hi,/* size n, upper bounds on x */
    NAPINT   const      n,/* problem dimension */
    NAPINT              K,/* number iterations in variable fixing method */
    NAPFLOAT    *breakpts,/* size n, breakpts [j] is br_hi[j] or br_lo[j] */
    NAPINT            *uf,/* size n, list of unfixed variables */
    NAPINT      *nunfixed,/* number of unfixed variables */
    NAPINT     *free_heap,/* size n+1, heap of free variables */
    NAPINT    *bound_heap,/* size n+1, heap of bound variables */
    int           goright,/* if true, move right, else move left */
    NAPstat         *Stat,/* solution statistics */
    NAPFLOAT const *br_lo,/* size n, br_lo[j] lo break pt for x[j] */
    NAPFLOAT const *br_hi,/* size n. br_hi[j] hi break pt for x[j] */
    int   recompute_slope,/* if true, then recompute slope */
    NAPparm         *Parm,/* parameters */
    int   const  loExists,/* TRUE when there are lower bound for x */
    int   const  hiExists /* TRUE when there are upper bound for x */
)
{
    int refine, status ;
    NAPINT jb, jfree, k, Dfree, nb, nf, Nb, Nf, nbound, nfree, nuf, nk ;
    NAPFLOAT a2sum, Aj, s, t, err,
             minbound, minfree, maxbound, maxfree, new_break, a2max ;
    const int lohiExist = (loExists && hiExists) ;

    /* initialization */
    nuf = *nunfixed ;
    err = Parm->err ; /* error threshhold that triggers refinement */
    refine = Parm->refine ; /* TRUE means to refine the solution */
    nbound = 0 ;   /* number of variables that start out bound */
    nfree = 0 ;    /* number of variables that start out free */
    nb = n ;       /* pointer to start of previously bound variables */
    nf = n ;       /* pointer to start of previously free variables */
    a2sum = NAPZERO ; /* sum aj*aj/dj for free variables */
    status = NAPHEAP_STATUS_KEEP_LOOKING ; /* default status */

    if ( goright ) /* move right */
    {
        /* d contains both positive and zero entries and lambda is to the
           left of the true multiplier.  Get ready to search over the
           break points to the right by constructing the heaps for currently
           bound and free variables, and by fixing variables whose break
           points are to the left.  Moreover, if the slope at lambda is
           not known, then compute it. */
        if ( recompute_slope )
        {
            *slope = NAPZERO ;
            *slopehi = NAPZERO ;
            *slopelo = NAPZERO ;
            if ( K > 0 ) /* variable fixing done, br_lo and br_hi exist */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT aj = a [j] ;
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        t = br_lo [j] ;
                        if ( t >= lambdaR ) /* j is fixed */
                        {
                            if ( aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            x [j] = t ;
                            *b -= aj*t ;
                            continue ;
                        }
                        else                     /* keep this variable */
                        {
                            s = br_hi [j] ;
                            if ( *lambda >= s ) /* j is fixed */
                            {
                                if ( aj > NAPZERO ) t = lo [j] ;
                                else                t = hi [j] ;
                                x [j] = t ;
                                *b -= aj*t ;
                                continue ;
                            }
                            if ( t > *lambda )   /* j is bound */
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                breakpts [j] = t ;
                                if ( aj > NAPZERO ) *slope += aj*hi [j] ;
                                else                *slope += aj*lo [j] ;
                            }
                            else                 /* j is free */
                            {
                                a2sum += aj*aj/dj ;
                                *slope += aj*(y [j] - aj*(*lambda))/dj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = s ;
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t > lambdaR )
                        {
                            if ( aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            if ( t > *lambda )
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                if ( aj > NAPZERO ) t = hi [j] ;
                                else                t = lo [j] ;
                                *slope += aj*t ;
                            }
                            else /* lambda = break point */
                            {
                                if ( aj > NAPZERO )
                                {
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*hi [j] :  NAPINF ;
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*lo [j] : -NAPINF ;
                                }
                                else
                                {
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*hi [j] : -NAPINF ;
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*lo [j] :  NAPINF ;
                                }
                            }
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else /* K = 0 */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT aj = a [j] ;
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        const NAPFLOAT yj = y [j] ;
                        if ( aj > NAPZERO )
                        {
                            if ( loExists &&
                               ((s = (yj - lo [j]*dj)/aj) <= *lambda) )
                            {
                                /* j is fixed */
                                x [j] = lo [j] ;
                                *b -= aj*lo [j] ;
                                continue ;
                            }
                            else
                            {
                                if ( hiExists )
                                {
                                    const NAPFLOAT hij = hi [j] ;
                                    t = (yj - hij*dj)/aj ;/* lo break point */
                                    if ( t >= lambdaR )   /* j is fixed */
                                    {
                                        x [j] = hij ;
                                        *b -= aj*hij ;
                                        continue ;
                                    }
                                    else                  /*keep this variable*/
                                    {
                                        if ( t > *lambda )/* j is bound */
                                        {
                                            *slope += aj*hij ;
                                            nbound++ ;
                                            bound_heap [nbound] = j ;
                                            breakpts [j] = t ;
                                        }
                                        else              /* j is free */
                                        {
                                            a2sum += aj*aj/dj ;
                                            *slope += aj*(yj - aj*(*lambda))/dj;
                                            breakpts [j] = s ;
                                            nfree++ ;
                                            free_heap [nfree] = j ;
                                        }
                                    }
                                }
                                else /* j is free */
                                {
                                    a2sum += aj*aj/dj ;
                                    *slope += aj*(yj - aj*(*lambda))/dj;
                                    breakpts [j] = NAPINF ;
                                    nfree++ ;
                                    free_heap [nfree] = j ;
                                }
                            }
                        }
                        else /* aj < 0 */
                        {
                            if ( hiExists &&
                                ((s = (yj - hi [j]*dj)/aj) <= *lambda) )
                            /* j is fixed */
                            {
                                x [j] = hi [j] ;
                                *b -= aj*hi [j] ;
                                continue ;
                            }
                            else
                            {
                                if ( loExists )
                                {
                                    const NAPFLOAT loj = lo [j] ;
                                    t = (yj - loj*dj)/aj ;/* lo break point */
                                    if ( t >= lambdaR )   /* j is fixed */
                                    {
                                        x [j] = loj ;
                                        *b -= aj*loj ;
                                        continue ;
                                    }
                                    else                  /*keep this variable*/
                                    {
                                        if ( t > *lambda )/* j is bound */
                                        {
                                            *slope += aj*loj ;
                                            nbound++ ;
                                            bound_heap [nbound] = j ;
                                            breakpts [j] = t ;
                                        }
                                        else              /* j is free */
                                        {
                                            a2sum += aj*aj/dj ;
                                            *slope += aj*(yj - aj*(*lambda))/dj;
                                            nfree++ ;
                                            free_heap [nfree] = j ;
                                            breakpts [j] = s ;
                                        }
                                    }
                                }
                                else
                                {
                                    a2sum += aj*aj/dj ;
                                    *slope += aj*(yj - aj*(*lambda))/dj;
                                    nfree++ ;
                                    free_heap [nfree] = j ;
                                    breakpts [j] = NAPINF ;
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t < *lambda ) /* fix xj */
                        {
                            if ( aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t > lambdaR )
                        {
                            if ( aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            if ( t > *lambda )
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                if ( aj > NAPZERO ) *slope += aj*hi [j] ;
                                else                *slope += aj*lo [j] ;
                            }
                            else /* lambda = break point */
                            {
                                if ( aj > NAPZERO )
                                {
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*hi [j] :  NAPINF ;
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*lo [j] : -NAPINF ;
                                }
                                else
                                {
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*hi [j] : -NAPINF ;
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*lo [j] :  NAPINF ;
                                }
                            }
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
            *slope -= *b ;
            if ( *slope + *slopelo <= NAPZERO ) /* lambda is optimal */
            {
                status = NAPHEAP_STATUS_OK ;
            }
            else
            {
                *slope += *slopelo ;
            }
        }
        else /* do not recompute slope */
        {
            if ( K > 0 ) /* variable fixing done, br_lo and br_hi exist */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        s = br_hi [j] ;
                        if ( s <= *lambda )           /* j is fixed */
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            x [j] = t ;
                            *b -= Aj*t ;
                            continue ;
                        }
                        else
                        {
                            t = br_lo [j] ;
                            if ( t  >= lambdaR )      /* j is fixed */
                            {
                                Aj = a [j] ;
                                if ( Aj > NAPZERO ) t = hi [j] ;
                                else                t = lo [j] ;
                                x [j] = t ;
                                *b -= Aj*t ;
                                continue ;
                            }
                            else                      /* keep this variable */
                            {
                                if ( t > *lambda )    /* j is bound */
                                {
                                    nbound++ ;
                                    bound_heap [nbound] = j ;
                                    breakpts [j] = t ;
                                }
                                else                  /* j is free */
                                {
                                    Aj = a [j] ;
                                    a2sum += Aj*Aj/dj ;
                                    nfree++ ;
                                    free_heap [nfree] = j ;
                                    breakpts [j] = s ;
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t <= *lambda )
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t > lambdaR )
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        const NAPFLOAT yj = y [j] ;
                        Aj = a [j] ;
                        if ( Aj > NAPZERO )
                        {
                            const NAPFLOAT loj = lo [j] ;
                            s = (yj - loj*dj)/Aj ;    /* hi break point */
                            if ( s <= *lambda )       /* j is fixed */
                            {
                                x [j] = loj ;
                                *b -= Aj*loj ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT hij = hi [j] ;
                                t = (yj - hij*dj)/Aj ;/* lo break point */
                                if ( t >= lambdaR )   /* j is fixed */
                                {
                                    x [j] = hij ;
                                    *b -= Aj*hij ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t > *lambda )/* j is bound */
                                    {
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += Aj*Aj/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                        else
                        {
                            const NAPFLOAT hij = hi [j] ;
                            s = (yj - hij*dj)/Aj ;    /* hi break point */
                            if ( s <= *lambda )       /* j is fixed */
                            {
                                x [j] = hij ;
                                *b -= Aj*hij ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT loj = lo [j] ;
                                t = (yj - loj*dj)/Aj ;/* lo break point */
                                if ( t >= lambdaR )   /* j is fixed */
                                {
                                    x [j] = loj ;
                                    *b -= Aj*loj ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t > *lambda )/* j is bound */
                                    {
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += Aj*Aj/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t <= *lambda ) /* fix xj */
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t > lambdaR )
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
        }

       /* recompute a2sum when it becomes much smaller than its max */
        a2max = a2sum ;

        Stat->nfree = nfree ;
        Stat->nbound = nbound ;
        if ( status == NAPHEAP_STATUS_OK ) /* lambda was optimal */
        {
            *nunfixed = nuf ;
            return ;
        }

        /* build minheap of free variables */
        napminheap_build (free_heap, breakpts, nfree) ;

        /* build minheap of bound variables */
        napminheap_build (bound_heap, breakpts, nbound) ;

        /* d contains both zero and nonzero entries, lambda is to the left
           of the true multiplier, and the break points are stored in a heap.
           Search over the break points to the right until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            minfree = breakpts [jfree] ;
        }
        else minfree = NAPINF ;
        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            minbound = breakpts [jb] ;
            while ( (minbound == *lambda) && nbound )
            {
                if ( d [jb] > NAPZERO )
                {
                    a2sum -= a [jb]*a [jb]/d [jb] ;
                }
                nbound = napminheap_delete(bound_heap, breakpts, nbound);
                if ( nbound )
                {
                    jb = bound_heap [1] ;
                    minbound = breakpts [jb] ;
                }
                else minbound = NAPINF ;
            }
        }
        else minbound = NAPINF ;

        /* recompute a2sum if it has significant decay */
        if ( a2sum <= Parm->decay*a2max )
        {
            a2sum = NAPZERO ;
            for (k = 1; k <= nfree; k++)
            {
                NAPINT j = free_heap [k] ;
                a2sum += a [j]*a [j]/d [j] ;
            }
            a2max = a2sum ;
        }

        while ( 1 )
        {
            NAPINT j ;
            if ( minfree < minbound )
            {
                new_break = minfree ;
                j = jfree ;
            }
            else
            {
                new_break = minbound ;
                j = jb ;
            }

            t = *slope - a2sum*(new_break - *lambda) ;
            if ( (t <= NAPZERO) || (new_break >= NAPINF) ) /* done */
            {
                if ( nfree && !refine ) *lambda += *slope/a2sum ;
                break ;
            }
            *lambda = new_break ;

            const NAPFLOAT dj = d [j] ;

            if ( dj ) *slope = t ;
            else
            {
                if ( lohiExist )
                {
                    *slope = t - fabs (a [j])*(hi [j] - lo [j]) ;
                    if ( *slope <= NAPZERO )
                    {
                        break ;
                    }
                }
                else
                {
                    break ;
                }
            }

            /* update the heaps */
            if ( *lambda == minfree ) /* only happens when dj > 0 */
            {
                /* delete break point from heap */
                nfree = napminheap_delete (free_heap, breakpts, nfree) ;

                /* add break point to list of previously free variables */
                free_heap [nf] = jfree ;
                nf-- ;

                /* update a2sum */
                a2sum -= a [jfree]*a [jfree]/dj ;

                /* recompute a2sum if it has significant decay */
                if ( a2sum <= Parm->decay*a2max )
                {
                    a2sum = NAPZERO ;
                    for (k = 1; k <= nfree; k++)
                    {
                        j = free_heap [k] ;
                        a2sum += a [j]*a [j]/d [j] ;
                    }
                    a2max = a2sum ;
                }

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    minfree = NAPINF ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;
                }
            }
            else
            {
                /* delete break point from heap */
                nbound  = napminheap_delete(bound_heap, breakpts, nbound);

                /* save break point in list of previously bound variables */
                bound_heap [nb] = jb ;
                nb-- ;

                if ( dj ) /* only do the following when dj > 0 */
                {
                    const NAPFLOAT aj = a [jb] ;
                    if ( K > 0 )
                    {
                        s = br_hi [jb] ;      /* new break point in br_hi */
                    }
                    else                      /* compute break point */
                    {
                        if ( aj > NAPZERO ) s = (y [j] - lo [j]*dj)/aj ;
                        else                s = (y [j] - hi [j]*dj)/aj ;
                    }

                    breakpts [jb] = s ;
                    nfree = napminheap_add (free_heap, breakpts, jb, nfree);

                    /* get the smallest entry in free heap */
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;

                    /* update a2sum */
                    a2sum += aj*aj/dj ;
                    if ( a2sum > a2max )
                    {
                        a2max = a2sum ;
                    }
                }

                /* get the smallest entry in bound heap */
                if ( nbound == 0 ) minbound = NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    minbound = breakpts [jb] ;
                }
            }
        }
        Stat->nbrks = (n-nb) + (n-nf) ;
    }
    else /* go left */
    {
        /* d contains both positive and zero entries and lambda is to the
           right of the true multiplier.  Get ready to search over the
           break points to the left by constructing the heaps for currently
           bound and free variables , and by fixing variables whose break
           points are to the right.  Moreover, if the slope at lambda is
           not known, then compute it. (*/
        if ( recompute_slope ) /* lambda was outside domain of dual function */
        {
            *slope = NAPZERO ;
            *slopehi = NAPZERO ;
            *slopelo = NAPZERO ;
            if ( K > 0 ) /* variable fixing done, br_lo and br_hi exist */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT aj = a [j] ;
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        t = br_hi [j] ;
                        if ( t <= lambdaL ) /* j is fixed */
                        {
                            if ( aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            x [j] = t ;
                            *b -= aj*t ;
                            continue ;
                        }
                        else                          /* keep this variable */
                        {
                            s = br_lo [j] ;
                            if ( *lambda <= s ) /* j is fixed */
                            {
                                if ( aj > NAPZERO ) t = hi [j] ;
                                else                t = lo [j] ;
                                x [j] = t ;
                                *b -= aj*t ;
                                continue ;
                            }
                            if ( t < *lambda )        /* j is bound */
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                breakpts [j] = t ;
                                if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                                else                *slope += aj*hi [j] ;
                            }
                            else                      /* j is free */
                            {
                                a2sum += aj*aj/dj ;
                                *slope += aj*(y [j] - aj*(*lambda))/dj ;
                                nfree++ ;
                                free_heap [nfree] = j ;
                                breakpts [j] = s ;
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t < lambdaL )
                        {
                            if ( aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            if ( t < *lambda )
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                                else                *slope += aj*hi [j] ;
                            }
                            else /* lambda = break point */
                            {
                                if ( aj > NAPZERO )
                                {
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*hi [j] :  NAPINF ;
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*lo [j] : -NAPINF ;
                                }
                                else
                                {
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*hi [j] : -NAPINF ;
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*lo [j] :  NAPINF ;
                                }
                            }
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else /* K = 0 */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT aj = a [j] ;
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        const NAPFLOAT yj = y [j] ;
                        if ( aj > NAPZERO )
                        {
                            const NAPFLOAT hij = hi [j] ;
                            s = (yj - hij*dj)/aj ;    /* lo break point */
                            if ( s >= *lambda )       /* j is fixed */
                            {
                                x [j] = hij ;
                                *b -= aj*hij ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT loj = lo [j] ;
                                t = (yj - loj*dj)/aj ;/* hi break point */
                                if ( t < lambdaL )    /* j is fixed */
                                {
                                    x [j] = loj ;
                                    *b -= aj*loj ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t < *lambda )/* j is bound */
                                    {
                                        *slope += aj*loj ;
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += aj*aj/dj ;
                                        *slope += aj*(yj - aj*(*lambda))/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                        else /* aj < 0 */
                        {
                            const NAPFLOAT loj = lo [j] ;
                            s = (yj - loj*dj)/aj ;    /* lo break point */
                            if ( s >= *lambda )       /* j is fixed */
                            {
                                x [j] = loj ;
                                *b -= aj*loj ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT hij = hi [j] ;
                                t = (yj - hij*dj)/aj ;/* hi break point */
                                if ( t <= lambdaL )   /* j is fixed */
                                {
                                    x [j] = hij ;
                                    *b -= aj*hij ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t < *lambda )/* j is bound */
                                    {
                                        *slope += aj*hij ;
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += aj*aj/dj ;
                                        *slope += aj*(yj - aj*(*lambda))/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t > *lambda ) /* fix xj */
                        {
                            if ( aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t < lambdaL )
                        {
                            if ( aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            if ( t < *lambda )
                            {
                                nbound++ ;
                                bound_heap [nbound] = j ;
                                if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                                else                *slope += aj*hi [j] ;
                            }
                            else
                            {
                                if ( aj > NAPZERO )
                                {
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*hi [j] :  NAPINF ;
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*lo [j] : -NAPINF ;
                                }
                                else
                                {
                                    *slopelo = (loExists) ?
                                             *slopelo + aj*hi [j] : -NAPINF ;
                                    *slopehi = (hiExists) ?
                                             *slopehi + aj*lo [j] :  NAPINF ;
                                }
                            }
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }

            *slope -= *b ;
            if ( *slope + *slopehi >= NAPZERO ) /* lambda is optimal */
            {
                status = NAPHEAP_STATUS_OK ;
            }
            else
            {
                *slope += *slopehi ;
            }
        }
        else /* do not recompute slope */
        {
            if ( K > 0 ) /* variable fixing done, br_lo and br_hi exist */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        s = br_lo [j] ;
                        if ( s >= *lambda )           /* j is fixed */
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            x [j] = t ;
                            *b -= Aj*t ;
                            continue ;
                        }
                        else
                        {
                            t = br_hi [j] ;
                            if ( t <= lambdaL )       /* j is fixed */
                            {
                                Aj = a [j] ;
                                if ( Aj > NAPZERO ) t = lo [j] ;
                                else                t = hi [j] ;
                                x [j] = t ;
                                *b -= Aj*t ;
                                continue ;
                            }
                            else                      /* keep this variable */
                            {
                                if ( t < *lambda )    /* j is bound */
                                {
                                    nbound++ ;
                                    bound_heap [nbound] = j ;
                                    breakpts [j] = t ;
                                }
                                else                  /* j is free */
                                {
                                    Aj = a [j] ;
                                    a2sum += Aj*Aj/dj ;
                                    nfree++ ;
                                    free_heap [nfree] = j ;
                                    breakpts [j] = s ;
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( t >= *lambda ) /* fix xj */
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t < lambdaL )
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
            else /* K = 0 */
            {
                LOOP_OVER_UNFIXED ;
                {
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        const NAPFLOAT yj = y [j] ;
                        const NAPFLOAT aj = a [j] ;
                        if ( aj > NAPZERO )
                        {
                            const NAPFLOAT hij = hi [j] ;
                            s = (yj - hij*dj)/aj ;    /* lo break point */
                            if ( s >= *lambda )       /* j is fixed */
                            {
                                x [j] = hij ;
                                *b -= aj*hij ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT loj = lo [j] ;
                                t = (yj - loj*dj)/aj ;/* hi break point */
                                if ( t < lambdaL )    /* j is fixed */
                                {
                                    x [j] = loj ;
                                    *b -= aj*loj ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t < *lambda )/* j is bound */
                                    {
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += aj*aj/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                        else
                        {
                            const NAPFLOAT loj = lo [j] ;
                            s = (yj - loj*dj)/aj ;    /* lo break point */
                            if ( s >= *lambda )       /* j is fixed */
                            {
                                x [j] = loj ;
                                *b -= aj*loj ;
                                continue ;
                            }
                            else
                            {
                                const NAPFLOAT hij = hi [j] ;
                                t = (yj - hij*dj)/aj ;/* hi break point */
                                if ( t <= lambdaL )   /* j is fixed */
                                {
                                    x [j] = hij ;
                                    *b -= aj*hij ;
                                    continue ;
                                }
                                else                  /* keep this variable*/
                                {
                                    if ( t < *lambda )/* j is bound */
                                    {
                                        nbound++ ;
                                        bound_heap [nbound] = j ;
                                        breakpts [j] = t ;
                                    }
                                    else              /* j is free */
                                    {
                                        a2sum += aj*aj/dj ;
                                        nfree++ ;
                                        free_heap [nfree] = j ;
                                        breakpts [j] = s ;
                                    }
                                }
                            }
                        }
                    }
                    else /* d [j] = 0 */
                    {
                        t = breakpts [j] ;
                        if ( *lambda <= t ) /* fix xj */
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = hi [j] ;
                            else                t = lo [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else if ( t < lambdaL )
                        {
                            Aj = a [j] ;
                            if ( Aj > NAPZERO ) t = lo [j] ;
                            else                t = hi [j] ;
                            *b -= Aj*t ;
                            x [j] = t ;
                            continue ;
                        }
                        else
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                        }
                    }
                }
                END_UNFIXED_LOOP ;
            }
        }

       /* recompute a2sum when it becomes much smaller than its max */
        a2max = a2sum ;

        Stat->nfree = nfree ;
        Stat->nbound = nbound ;
        if ( status == NAPHEAP_STATUS_OK ) /* lambda was optimal */
        {
            *nunfixed = nuf ;
            return ;
        }

        /* build maxheap of free variables */
        napmaxheap_build (free_heap, breakpts, nfree) ;

        /* build maxheap of bound variables */
        napmaxheap_build (bound_heap, breakpts, nbound) ;

        /* move through break points until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            maxfree = breakpts [jfree] ;
        }
        else maxfree = -NAPINF ;
        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            maxbound = breakpts [jb] ;
            while ( (maxbound == *lambda) && nbound )
            {
                if ( d [jb] > NAPZERO )
                {
                    a2sum -= a [jb]*a [jb]/d [jb] ;
                }
                nbound = napmaxheap_delete(bound_heap, breakpts, nbound);
                if ( nbound )
                {
                    jb = bound_heap [1] ;
                    maxbound = breakpts [jb] ;
                }
                else maxbound = -NAPINF ;
            }
        }
        else maxbound = -NAPINF ;

        /* recompute a2sum if it has significant decay */
        if ( a2sum <= Parm->decay*a2max )
        {
            a2sum = NAPZERO ;
            for (k = 1; k <= nfree; k++)
            {
                NAPINT j = free_heap [k] ;
                a2sum += a [j]*a [j]/d [j] ;
            }
            a2max = a2sum ;
        }

        while ( 1 )
        {
            NAPINT j ;
            if ( maxfree > maxbound )
            {
                new_break = maxfree ;
                j = jfree ;
            }
            else
            {
                new_break = maxbound ;
                j = jb ;
            }

            t = *slope - a2sum*(new_break - *lambda) ;
            if ( (t > NAPZERO) || (new_break <= -NAPINF) ) /* done */
            {
                if ( nfree && !refine ) *lambda += *slope/a2sum ;
                break ;
            }
            *lambda = new_break ;

            const NAPFLOAT dj = d [j] ;
            if ( dj > NAPZERO ) *slope = t ;
            else
            {
                if ( lohiExist )
                {
                    *slope = t + fabs (a [j])*(hi [j] - lo [j]) ;
                    if ( *slope >= NAPZERO )
                    {
                        break ;
                    }
                }
                else
                {
                    break ;
                }
            }

            /* update the heaps */
            if ( *lambda == maxfree ) /* only happens when dj > 0 */
            {
                /* delete break point from heap */
                nfree = napmaxheap_delete (free_heap, breakpts, nfree) ;

                /* add break point to list of previously free variables */
                free_heap [nf] = jfree ;
                nf-- ;

                /* update a2sum */
                a2sum -= a [jfree]*a [jfree]/dj ;

                /* recompute a2sum if it has significant decay */
                if ( a2sum <= Parm->decay*a2max )
                {
                    a2sum = NAPZERO ;
                    for (k = 1; k <= nfree; k++)
                    {
                        j = free_heap [k] ;
                        a2sum += a [j]*a [j]/d [j] ;
                    }
                    a2max = a2sum ;
                }

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    maxfree = -NAPINF ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;
                }
            }

            else
            {
                /* delete break point from heap */
                nbound = napmaxheap_delete(bound_heap, breakpts, nbound);

                /* add break point to list of previously bound variables */
                bound_heap [nb] = jb ;
                nb-- ;

                if ( dj ) /* only do the following when dj > 0 */
                {
                    const NAPFLOAT aj = a [jb] ;
                    if ( K > 0 )
                    {
                        s = br_lo [jb] ; /* new break point in br_lo */
                    }
                    else                 /* compute break point */
                    {
                        if ( aj > NAPZERO )
                        {
                            if ( hiExists ) s = (y [j] - hi [j]*dj)/aj ;
                            else            s = -NAPINF ;
                        }
                        else
                        {
                            if ( loExists ) s = (y [j] - lo [j]*dj)/aj ;
                            else            s = -NAPINF ;
                        }
                    }

                    /* store new break point */
                    breakpts [jb] = s ;

                    /* add new break point to free heap */
                    nfree = napmaxheap_add (free_heap, breakpts, jb, nfree);

                    /* get the smallest entry in free heap */
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;

                    /* update a2sum */
                    a2sum += aj*aj/dj ;
                    if ( a2sum > a2max )
                    {
                        a2max = a2sum ;
                    }
                }

                /* get the largest entry in bound heap */
                if ( nbound == 0 ) maxbound = -NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    maxbound = breakpts [jb] ;
                }
            }
        }
        Stat->nbrks = (n-nb) + (n-nf) ;
    }

    if ( refine )
    {
        /* evaluate slope at lambda */
        *slopehi  = NAPZERO ; /* upper bound on slope at given lambda */
        *slopelo  = NAPZERO ; /* lower bound on slope at given lambda */
        *slope = NAPZERO ;    /* slope ignoring any break point at lambda */

        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            const NAPFLOAT aj = a [j] ;
            const NAPFLOAT dj = d [j] ;
            if ( dj > NAPZERO )
            {
                t = (y [j] - *lambda*aj)/dj ;
                if      ( loExists && (t < lo [j]) ) t = lo [j] ;
                else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
                *slope += aj*t ;
            }
            else
            {
                t = breakpts [j] ;
                /* update the slope of dual function */
                if ( *lambda < t )
                {
                    if ( aj > NAPZERO ) *slope += aj*hi [j] ;
                    else                *slope += aj*lo [j] ;
                }
                else if ( *lambda > t )
                {
                    if ( aj > NAPZERO ) *slope += aj*lo [j] ;
                    else                *slope += aj*hi [j] ;
                }
                else /* lambda is a break point */
                {
                    if ( aj > NAPZERO )
                    {
                        *slopehi = (hiExists) ?
                                 *slopehi + aj*hi [j] :  NAPINF ;
                        *slopelo = (loExists) ?
                                 *slopelo + aj*lo [j] : -NAPINF ;
                    }
                    else
                    {
                        *slopelo = (loExists) ?
                                 *slopelo + aj*hi [j] : -NAPINF ;
                        *slopehi = (hiExists) ?
                                 *slopehi + aj*lo [j] :  NAPINF ;
                    }
                }
            }
        END_LOOP ;
        *slope -= *b ;

        /* check if lambda is optimal */
        if ( (*slope+*slopelo <= NAPZERO) && (*slope+*slopehi >= NAPZERO) )
        {
            *nunfixed = nuf ;
            return ;
        }
        Nb = nb ;
        Nf = nf ;
        if ( goright )
        {
            if ( *slope + *slopelo >  err )
            {
                *slope += *slopelo ;
                /* lambda is to the left of the true multiplier, and the break
                   points are stored in a heap.  Search over the break points
                   to the right until finding 0 slope */
                if ( nfree > 0 )
                {
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;
                }
                else minfree = NAPINF ;
                if ( nbound > 0 )
                {
                    jb = bound_heap [1] ;
                    minbound = breakpts [jb] ;
                    while ( (minbound == *lambda) && nbound )
                    {
                        if ( d [jb] > NAPZERO )
                        {
                            a2sum -= a [jb]*a [jb]/d [jb] ;
                        }
                        nbound = napminheap_delete(bound_heap, breakpts,
                                                   nbound) ;
                        if ( nbound )
                        {
                            jb = bound_heap [1] ;
                            minbound = breakpts [jb] ;
                        }
                        else minbound = NAPINF ;
                    }
                }
                else minbound = NAPINF ;

                while ( 1 )
                {
                    NAPINT j ;
                    if ( minfree < minbound )
                    {
                        new_break = minfree ;
                        j = jfree ;
                    }
                    else
                    {
                        new_break = minbound ;
                        j = jb ;
                    }

                    t = *slope - a2sum*(new_break - *lambda) ;

                    if ( (t <= NAPZERO) || (new_break >= NAPINF) ) /* done */
                    {
                        if ( nfree ) *lambda += *slope/a2sum ;
                        break ;
                    }
                    *lambda = new_break ;

                    const NAPFLOAT dj = d [j] ;
                    if ( dj ) *slope = t ;
                    else
                    {
                        if ( lohiExist )
                        {
                            *slope = t - fabs (a [j])*(hi [j] - lo [j]) ;
                            if ( *slope <= NAPZERO )
                            {
                                break ;
                            }
                        }
                        else
                        {
                            break ;
                        }
                    }

                    /* update the heaps */
                    if ( *lambda == minfree ) /* only happens when dj > 0 */
                    {
                        /* delete break point from heap */
                        nfree = napminheap_delete (free_heap, breakpts, nfree) ;

                        /* add break point to previously free list */
                        free_heap [nf] = jfree ;
                        nf-- ;

                        /* update a2sum */
                        a2sum -= a [jfree]*a [jfree]/dj ;

                        /* get the smallest entry in heap */
                        if ( nfree == 0 )
                        {
                            minfree = NAPINF ;
                            if ( a2sum < NAPZERO ) a2sum = NAPZERO ;
                        }
                        else
                        {
                            jfree = free_heap [1] ;
                            minfree = breakpts [jfree] ;
                        }
                    }
                    else
                    {
                        /* delete break point from heap */
                        nbound  = napminheap_delete(bound_heap, breakpts,
                                                    nbound) ;

                        /* save break point in previously bound list */
                        bound_heap [nb] = jb ;
                        nb-- ;

                        if ( dj ) /* only do the following when dj > 0 */
                        {
                            const NAPFLOAT aj = a [jb] ;
                            if ( K > 0 )
                            {
                                s = br_hi [jb] ;  /* new break point in br_hi */
                            }
                            else                  /* compute break point */
                            {
                                if ( aj > NAPZERO )
                                {
                                    if ( loExists ) s = (y [j] - lo [j]*dj)/aj ;
                                    else            s = NAPINF ;
                                }
                                else
                                {
                                    if ( hiExists ) s = (y [j] - hi [j]*dj)/aj ;
                                    else            s = NAPINF ;
                                }
                            }

                            breakpts [jb] = s ;
                            nfree = napminheap_add (free_heap, breakpts, jb,
                                                    nfree);

                            /* get the smallest entry in free heap */
                            jfree = free_heap [1] ;
                            minfree = breakpts [jfree] ;

                            /* update a2sum */
                            a2sum += aj*aj/dj ;
                        }

                        /* get the smallest entry in bound heap */
                        if ( nbound == 0 ) minbound = NAPINF ;
                        else
                        {
                            jb = bound_heap [1] ;
                            minbound = breakpts [jb] ;
                        }
                    }
                }
                Stat->nrefine = (Nb - nb) + (Nf - nf) ;
            }
            else if ( *slope + *slopehi < -err )
            {
                *slope += *slopehi ;
                Dfree = 0 ; /* change in number of free variable */
                if ( nb < n )
                {
                    maxbound = *lambda ;
                    while ( (maxbound == *lambda) && (nb < n) )
                    {
                        nb++ ;
                        jb = bound_heap [nb] ;
                        const NAPFLOAT dj = d [jb] ;
                        if ( dj > NAPZERO )
                        {
                            const NAPFLOAT aj = a [jb] ;
                            if ( K > 0 )
                            {
                                maxbound = br_lo [jb] ;
                            }
                            else
                            {
                                if ( aj > NAPZERO )
                                {
                                     maxbound = (y [jb]-hi [jb]*dj)/aj ;
                                }
                                else maxbound = (y [jb]-lo [jb]*dj)/aj ;
                            }
                            if ( maxbound == *lambda )
                            {
                                Dfree-- ;
                                a2sum -= aj*aj/dj ;
                            }
                        }
                        else maxbound = breakpts [jb] ;
                    }
                    if ( maxbound == *lambda ) maxbound = -NAPINF ;
                }
                else maxbound = -NAPINF ;

                if ( nf < n )
                {
                    nf++ ;
                    jfree = free_heap [nf] ;
                    maxfree = breakpts [jfree] ;
                }
                else maxfree = -NAPINF ;

                Nb = nb ;
                Nf = nf ;

                while ( (maxfree > -NAPINF) || (maxbound > -NAPINF) )
                {
                    NAPINT j ;
                    if ( maxfree >= maxbound )
                    {
                        new_break = maxfree ;
                        j = jfree ;
                    }
                    else
                    {
                        new_break = maxbound ;
                        j = jb ;
                    }
                    t = *slope - a2sum*(new_break - *lambda) ;
                    if ( t >= NAPZERO ) /* done */
                    {
                        break ;
                    }
                    *lambda = new_break ;

                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        *slope = t ;
                    }
                    else
                    {
                        if ( lohiExist )
                        {
                            *slope = t + fabs (a [j])*(hi [j] - lo [j]) ;
                            if ( *slope >= NAPZERO )
                            {
                                *lambda = new_break ;
                                *slope = NAPZERO ;
                                break ;
                            }
                        }
                        else
                        {
                            *lambda = new_break ;
                            *slope = NAPZERO ;
                            break ;
                        }
                    }

                    if ( *lambda == maxfree )
                    {
                        Dfree++ ;
                        a2sum += a [j]*a [j]/dj ;   /* becomes free */
                        nf++ ;
                        if ( nf <= n )
                        {
                            jfree = free_heap [nf] ;
                            maxfree = breakpts [jfree] ;
                        }
                        else maxfree = -NAPINF ;
                    }
                    else
                    {
                        if ( dj > NAPZERO )
                        {
                            Dfree-- ;
                            a2sum -= a [j]*a [j]/dj ; /* becomes bound */
                        }
                        nb++ ;
                        if ( nb <= n )
                        {
                            jb = bound_heap [nb] ;
                            if ( d [jb] )
                            {
                                if ( K > 0 )
                                {
                                    maxbound = br_lo [jb] ;
                                }
                                else
                                {
                                    const NAPFLOAT aj = a [jb] ;
                                    if ( aj > NAPZERO )
                                    {
                                        maxbound = (y [jb] - hi [jb]*d [jb])/aj;
                                    }
                                    else
                                    {
                                        maxbound = (y [jb] - lo [jb]*d [jb])/aj;
                                    }
                                }
                            }
                            else maxbound = breakpts [jb] ;
                        }
                        else maxbound = -NAPINF ;
                    }
                }
                if ( nfree + Dfree ) *lambda += *slope/a2sum ;
                Stat->nrefine = (nb-Nb) + (nf-Nf) ;
            }
        }
        else
        {
            if ( *slope + *slopehi < -err )
            {
                *slope += *slopehi ;
                /* lambda is to the right of the true multiplier, and the break
                   points are stored in a heap.  Search over the break points
                   to the right until finding 0 slope */
                if ( nfree > 0 )
                {
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;
                }
                else maxfree = -NAPINF ;
                if ( nbound > 0 )
                {
                    jb = bound_heap [1] ;
                    maxbound = breakpts [jb] ;
                    while ( (maxbound == *lambda) && nbound )
                    {
                        if ( d [jb] > NAPZERO )
                        {
                            a2sum -= a [jb]*a [jb]/d [jb] ;
                        }
                        nbound = napmaxheap_delete(bound_heap, breakpts,
                                                   nbound);
                        if ( nbound )
                        {
                            jb = bound_heap [1] ;
                            maxbound = breakpts [jb] ;
                        }
                        else maxbound = -NAPINF ;
                    }
                }
                else maxbound = -NAPINF ;

                while ( 1 )
                {
                    NAPINT j ;
                    if ( maxfree > maxbound )
                    {
                        new_break = maxfree ;
                        j = jfree ;
                    }
                    else
                    {
                        new_break = maxbound ;
                        j = jb ;
                    }

                    t = *slope - a2sum*(new_break - *lambda) ;
                    if ( (t > NAPZERO) || (new_break <= -NAPINF) ) /* done */
                    {
                        if ( nfree ) *lambda += *slope/a2sum ;
                        break ;
                    }
                    *lambda = new_break ;

                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO ) *slope = t ;
                    else
                    {
                        if ( lohiExist )
                        {
                            *slope = t + fabs (a [j])*(hi [j] - lo [j]) ;
                            if ( *slope >= NAPZERO )
                            {
                                break ;
                            }
                        }
                        else
                        {
                            break ;
                        }
                    }

                    /* update the heaps */
                    if ( *lambda == maxfree ) /* only happens when dj > 0 */
                    {
                        /* delete break point from heap */
                        nfree = napmaxheap_delete (free_heap, breakpts, nfree) ;

                        /* add break point to previously free list */
                        free_heap [nf] = jfree ;
                        nf-- ;

                        /* update a2sum */
                        a2sum -= a [jfree]*a [jfree]/dj ;

                        /* get the smallest entry in heap */
                        if ( nfree == 0 )
                        {
                            maxfree = -NAPINF ;
                            if ( a2sum < NAPZERO ) a2sum = NAPZERO ;
                        }
                        else
                        {
                            jfree = free_heap [1] ;
                            maxfree = breakpts [jfree] ;
                        }
                    }

                    else
                    {
                        /* delete break point from heap */
                        nbound = napmaxheap_delete(bound_heap, breakpts,
                                                   nbound) ;

                        /* add break point to previously bound list */
                        bound_heap [nb] = jb ;
                        nb-- ;

                        if ( dj ) /* only do the following when dj > 0 */
                        {
                            const NAPFLOAT aj = a [jb] ;
                            if ( K > 0 )
                            {
                                s = br_lo [jb] ; /* new break point in br_lo */
                            }
                            else                 /* compute break point */
                            {
                                if ( aj > NAPZERO )
                                {
                                    if ( hiExists ) s = (y [j] - hi [j]*dj)/aj ;
                                    else            s = -NAPINF ;
                                }
                                else
                                {
                                    if ( loExists ) s = (y [j] - lo [j]*dj)/aj ;
                                    else            s = -NAPINF ;
                                }
                            }

                            /* store new break point */
                            breakpts [jb] = s ;

                            /* add new break point to free heap */
                            nfree = napmaxheap_add (free_heap, breakpts, jb,
                                                    nfree);

                            /* get the smallest entry in free heap */
                            jfree = free_heap [1] ;
                            maxfree = breakpts [jfree] ;

                            /* update a2sum */
                            a2sum += aj*aj/dj ;
                        }

                        /* get the largest entry in bound heap */
                        if ( nbound == 0 ) maxbound = -NAPINF ;
                        else
                        {
                            jb = bound_heap [1] ;
                            maxbound = breakpts [jb] ;
                        }
                    }
                }
                Stat->nbrks = (Nb - nb) + (Nf - nf) ;
            }
            else if ( *slope + *slopelo >  err )
            {
                *slope += *slopelo ;
                Dfree = 0 ; /* change in number of free variables */
                if ( nb < n )
                {
                    minbound = *lambda ;
                    while ( (minbound == *lambda) && (nb < n) )
                    {
                        nb++ ;
                        jb = bound_heap [nb] ;
                        const NAPFLOAT dj = d [jb] ;
                        if ( dj > NAPZERO )
                        {
                            const NAPFLOAT aj = a [jb] ;
                            if ( K > 0 )
                            {
                                minbound = br_hi [jb] ;
                            }
                            else
                            {
                                if ( aj > NAPZERO )
                                {
                                     if ( loExists )
                                             minbound = (y [jb]-lo [jb]*dj)/aj ;
                                     else    minbound = NAPINF ;
                                }
                                else
                                {
                                     if ( hiExists )
                                             minbound = (y [jb]-hi [jb]*dj)/aj ;
                                     else    minbound = NAPINF ;
                                }
                            }
                            if ( minbound == *lambda )
                            {
                                Dfree-- ;
                                a2sum -= aj*aj/dj ;
                            }
                        }
                        else minbound = breakpts [jb] ;
                    }
                    if ( minbound == *lambda ) minbound = NAPINF ;
                }
                else minbound = NAPINF ;

                if ( nf < n )
                {
                    nf++ ;
                    jfree = free_heap [nf] ;
                    minfree = breakpts [jfree] ;
                }
                else minfree = NAPINF ;

                Nb = nb ;
                Nf = nf ;

                while ( (minfree < NAPINF) || (minbound < NAPINF) )
                {
                    NAPINT j ;
                    if ( minfree <= minbound )
                    {
                        new_break = minfree ;
                        j = jfree ;
                    }
                    else
                    {
                        new_break = minbound ;
                        j = jb ;
                    }
                    t = *slope - a2sum*(new_break - *lambda) ;
                    if ( t <= NAPZERO ) /* done */
                    {
                        break ;
                    }
                    *lambda = new_break ;
                    const NAPFLOAT dj = d [j] ;
                    if ( dj > NAPZERO )
                    {
                        *slope = t ;
                    }
                    else
                    {
                        if ( lohiExist )
                        {
                            *slope = t - fabs (a [j])*(hi [j] - lo [j]) ;
                            if ( *slope <= NAPZERO )
                            {
                                *lambda = new_break ;
                                *slope = NAPZERO ;
                                break ;
                            }
                        }
                        else
                        {
                            *lambda = new_break ;
                            *slope = NAPZERO ;
                            break ;
                        }
                    }

                    if ( *lambda == minfree )
                    {
                        Dfree++ ;
                        a2sum += a [j]*a [j]/dj ;     /* becomes free */
                        nf++ ;
                        if ( nf <= n )
                        {
                            jfree = free_heap [nf] ;
                            minfree = breakpts [jfree] ;
                        }
                        else minfree = NAPINF ;
                    }
                    else
                    {
                        if ( dj > NAPZERO )
                        {
                            Dfree-- ;
                            a2sum -= a [j]*a [j]/dj ; /* becomes bound */
                        }
                        nb++ ;
                        if ( nb <= n )
                        {
                            jb = bound_heap [nb] ;
                            if ( d [jb] )
                            {
                                if ( K > 0 )
                                {
                                    minbound = br_hi [jb] ;
                                }
                                else
                                {
                                    const NAPFLOAT aj = a [jb] ;
                                    if ( aj > NAPZERO )
                                    {
                                        if ( loExists ) minbound =
                                                   (y [jb] - lo [jb]*d [jb])/aj;
                                        else            minbound = NAPINF ;
                                    }
                                    else
                                    {
                                        if ( hiExists ) minbound =
                                                   (y [jb] - hi [jb]*d [jb])/aj;
                                        else            minbound = NAPINF ;
                                    }
                                }
                            }
                            else minbound = breakpts [jb] ;
                        }
                        else minbound = NAPINF ;
                    }
                }
                if ( nfree + Dfree ) *lambda += *slope/a2sum ;
                Stat->nrefine = (nb-Nb) + (nf-Nf) ;
            }
        }
    }
    *nunfixed = nuf ;
}

/*  =========================================================================
    === napfix0 =============================================================
    =========================================================================
    d is zero, the optimal dual solution lambda has been determined,
    fix all remaining unfixed components of x except those associated
    with any breakpoints coinciding with lambda.
    =========================================================================*/

PRIVATE void napfix0
(
    NAPFLOAT        *x, /* size n. solution (output) */
    NAPFLOAT const  *a, /* size n, linear constraint vector */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPFLOAT        *b, /* b - ai*xi for fixed variables */
    NAPFLOAT    lambda, /* optimal multiplier */
    NAPINT         *uf, /* size n, list of unfixed variables */
    NAPINT   *nunfixed, /* number of unfixed variables */
    NAPFLOAT const *breakpts /* break points */
)
{
    NAPFLOAT aj, s, t ;
    NAPINT k, nk, nuf ;

    /* set all variables for which the break point != lambda */
    nuf = *nunfixed ;
    LOOP_OVER_UNFIXED ;
    {
        s = breakpts [j] ;
        aj = a [j] ;
        if ( s < lambda )
        {
            if ( aj > NAPZERO ) t = lo [j] ;
            else                t = hi [j] ;
            x [j] = t ;
            *b -= aj*t ;
            continue ;
        }
        else if ( s > lambda )
        {
            if ( aj > NAPZERO ) t = hi [j] ;
            else                t = lo [j] ;
            x [j] = t ;
            *b -= aj*t ;
            continue ;
        }
    }
    END_UNFIXED_LOOP ;
    *nunfixed = nuf ;
}

/*  =========================================================================
    === napfix1 =============================================================
    =========================================================================
    d can have both positive and zero entries, the optimal dual multiplier
    lambda has been determined, fix all remaining unfixed components of
    x except those associated with any breakpoints coinciding with lambda.
    =========================================================================*/

PRIVATE void napfix1
(
    NAPFLOAT        *x, /* size n. solution (output) */
    NAPFLOAT const  *a, /* size n, linear constraint vector */
    NAPFLOAT const  *y, /* size n. linear term in objective function */
    NAPFLOAT const  *d, /* size n, diagonal of objective Hessian */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPFLOAT        *b, /* b - ai*xi for fixed variables */
    NAPFLOAT    lambda, /* optimal multiplier */
    NAPINT         *uf, /* size n, list of unfixed variables */
    NAPINT   *nunfixed, /* number of unfixed variables */
    int const loExists, /* TRUE when there are lower bound for x */
    int const hiExists, /* TRUE when there are upper bound for x */
    NAPFLOAT const *breakpts/* break points */
)
{
    NAPFLOAT aj, s, t ;
    NAPINT k, nk, nuf ;
    /* set all variables for which the break point != lambda */
    nuf = *nunfixed ;
    LOOP_OVER_UNFIXED ;
    {
        aj = a [j] ;
        if ( d [j] > NAPZERO )
        {
            t = (y [j] - lambda*aj)/d [j] ;
            if      ( loExists && (t < lo [j]) ) t = lo [j] ;
            else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
            *b -= aj*t ;
            x [j] = t ;
            continue ;
        }
        else
        {
            s = breakpts [j] ;
            /* update the slope of dual function */
            if ( lambda < s )
            {
                if ( aj > NAPZERO ) t = hi [j] ;
                else                t = lo [j] ;
                *b -= aj*t ;
                x [j] = t ;
                continue ;
            }
            else if ( lambda > s )
            {
                if ( aj > NAPZERO ) t = lo [j] ;
                else                t = hi [j] ;
                *b -= aj*t ;
                x [j] = t ;
                continue ;
            }
        }
    }
    END_UNFIXED_LOOP ;
    *nunfixed = nuf ;
}

/*  =========================================================================
    === napsolution =========================================================
    =========================================================================
    d is positive and the optimal dual solution lambda has been determined.
    Evaluate the optimal primal solution.
    =========================================================================*/

PRIVATE void napsolution
(
    NAPFLOAT        *x, /* size n, solution (output) */
    NAPFLOAT const  *a, /* size n, coefficient of linear constraint */
    NAPFLOAT const  *y, /* size n, linear term in objective */
    NAPFLOAT const *ay, /* size n, linear term y in objective over a */
    NAPFLOAT const *ad, /* size n, coefficient of linear constraint over d */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPFLOAT    lambda, /* optimal multiplier */
    NAPINT   const *uf, /* size n, unfixed variables */
    NAPINT   const *kf, /* size n, known free variables */
    NAPINT         nuf, /* number of unfixed variables */
    NAPINT         nkf, /* number of known free variables */
    int const loExists, /* TRUE when there are lower bound for x */
    int const hiExists, /* TRUE when there are upper bound for x */
    int const d_is_one  /* TRUE when diagonal is identically one */
)
{
    NAPFLOAT t ;
    NAPINT k ;

    if ( d_is_one )
    {
        /* set unbound variables */
        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            t = y [j] - lambda*a [j] ;
            if      ( loExists && (t < lo [j]) ) t = lo [j] ;
            else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
            x [j] = t ;
        END_LOOP
    
        /* set free variables */
        for (k = 0; k < nkf; k++)
        {
            NAPINT j = kf [k] ;
            x [j] = y [j] - lambda*a [j];
        }
    }
    else
    {
        /* set unbound variables */
        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            t = (ay [j] - lambda)*ad [j] ;
            if      ( loExists && (t < lo [j]) ) t = lo [j] ;
            else if ( hiExists && (t > hi [j]) ) t = hi [j] ;
            x [j] = t ;
        END_LOOP
    
        /* set free variables */
        for (k = 0; k < nkf; k++)
        {
            NAPINT j = kf [k] ;
            x [j] = (ay [j] - lambda)*ad [j];
        }
    }
}

/*  ==========================================================================
    === napsolution0 =========================================================
    ==========================================================================
    d is either zero or partly zero.  All the components of x are fixed
    except for the components corresponding to break points that are equal
    to lambda. These remaining components of x are determined by solving
    a least squares problem. Let X, A, LO, and HI denote the subvectors
    corresponding to these undetermined components.  We solve a problem
    of the form

                 min X'X subject to A'X = B, LO <= X <= HI

    to obtain the remaining components of x.
    ========================================================================= */

PRIVATE void napsolution0
(
    NAPFLOAT        *x, /* size n. solution (output) */
    NAPFLOAT const  *a, /* size n, linear constraint vector */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPFLOAT         B, /* the constraint is A'X = B */
    NAPFLOAT *breakpts, /* size n, breakpts [j] is br_hi[j] or br_lo[j] */
    NAPINT         *uf, /* size n, list of unfixed variables */
    NAPINT         nuf, /* number of unfixed variables */
    NAPINT  *free_heap, /* size n+1, heap of free variables */
    NAPINT *bound_heap, /* size n+1, heap of bound variables */
    int const loExists, /* TRUE when there are lower bound for x */
    int const hiExists  /* TRUE when there are upper bound for x */
)
{
    NAPINT jb, jfree, k, nk, nbound, nfree ;
    NAPFLOAT a2sum, aj, lambda, slope, s, t, maxbound, maxfree, minbound,
           minfree, new_break ;

    if ( nuf == 0 ) return ; /* no undetermined components */

    /* initialization */
    nbound = 0 ;      /* counts number of bound variables */
    nfree = 0 ;       /* counts number of free variables */
    a2sum = NAPZERO ; /* sum aj*aj for free variables */
    lambda = NAPZERO ;/* starting guess for multiplier */
    slope = NAPZERO ; /* slope initialization */

    /* evaluate the slope at lambda = 0 */
    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
        if ( hiExists && (hi [j] < NAPZERO) )
        {
            slope += a [j]*hi [j] ;
        }
        else if ( loExists && (lo [j] > NAPZERO) )
        {
            slope += a [j]*lo [j] ;
        }
        /* else min attained at x [j] = 0 */
    END_LOOP ;
    slope -= B ;
    if ( slope > NAPZERO ) /* move right */
    {
        /* d is positive and lambda = 0 is to the left of the true multiplier.
           Get ready to search over the break points to the right by
           constructing the heaps for currently bound and free variables,
           and by fixing variables whose break points are to the left. */
        LOOP_OVER_UNFIXED ;
        {
            aj = a [j] ;
            if ( aj > NAPZERO )
            {
                const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                s = -loj/aj ;        /* hi break point */
                if ( s <= NAPZERO )     /* j is fixed */
                {
                    x [j] = loj ;
                    continue ;
                }
                else
                {
                    if ( hiExists )
                    {
                        t = -hi [j]/aj ;    /* lo break point */
                        if ( t > NAPZERO )  /* j is bound */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = t ;
                        }
                        else             /* j is free */
                        {
                            a2sum += aj*aj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = s ;
                        }
                    }
                    else
                    {
                        a2sum += aj*aj ;
                        nfree++ ;
                        free_heap [nfree] = j ;
                        breakpts [j] = s ;
                    }
                }
            }
            else /* aj < 0 */
            {
                const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                s = -hij/aj ;        /* hi break point */
                if ( s <= NAPZERO )     /* j is fixed */
                {
                    x [j] = hij ;
                    continue ;
                }
                else
                {
                    if ( loExists )
                    {
                        t = -lo [j]/aj ;    /* lo break point */
                        if ( t > NAPZERO )  /* j is bound */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = t ;
                        }
                        else             /* j is free */
                        {
                            a2sum += aj*aj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = s ;
                        }
                    }
                    else
                    {
                        a2sum += aj*aj ;
                        nfree++ ;
                        free_heap [nfree] = j ;
                        breakpts [j] = s ;
                    }
                }
            }
        }
        END_UNFIXED_LOOP ;

        /* build heap for free variables */
        napminheap_build (free_heap, breakpts, nfree) ;

        /* build heap for bound variables */
        napminheap_build (bound_heap, breakpts, nbound) ;

        /* d is positive, lambda is to the left of the true multiplier, and
           the break points are stored in a heap.  Search over the break points
           to the right until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            minfree = breakpts [jfree] ;
        }
        else minfree = NAPINF ;

        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            minbound = breakpts [jb] ;
        }
        else minbound = NAPINF ;

        while ( 1 )
        {
            new_break = MIN (minfree, minbound) ;
            t = slope - a2sum*(new_break - lambda) ;
            if ( (t <= NAPZERO) || (new_break >= NAPINF) ) /* done */
            {
                /* When refine is TRUE, better to do last update in
                   refinement phase */
                if ( nfree ) lambda += slope/a2sum ;
                break ;
            }
            lambda = new_break ;
            slope = t ;

            /* update the heaps */
            while ( lambda == minfree )
            {
                /* delete break point from heap */
                nfree = napminheap_delete (free_heap, breakpts, nfree) ;

                /* update a2sum */
                a2sum -= a [jfree]*a [jfree] ;

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    minfree = NAPINF ;
                    if ( a2sum < NAPZERO ) a2sum = NAPZERO ;
                    break ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    minfree = breakpts [jfree] ;
                }
            }

            while ( lambda == minbound )
            {
                /* delete break point from heap */
                nbound  = napminheap_delete(bound_heap, breakpts, nbound);

                /* compute new hi break point */
                aj = a [jb] ;
                if ( aj > NAPZERO )
                {
                    if ( loExists ) s = -lo [jb]/aj ;
                    else            s = NAPINF ;
                }
                else
                {
                    if ( hiExists ) s = -hi [jb]/aj ;
                    else            s = NAPINF ;
                }
                breakpts [jb] = s ;

                /* add new break point to free heap */
                nfree = napminheap_add (free_heap, breakpts, jb, nfree) ;

                /* get the smallest entry in free heap */
                jfree = free_heap [1] ;
                minfree = breakpts [jfree] ;

                /* update a2sum */
                a2sum += aj*aj ;

                /* get the smallest entry in bound heap */
                if ( nbound == 0 ) minbound = NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    minbound = breakpts [jb] ;
                }
            }
        }
    }
    else if ( slope < NAPZERO ) /* move left */
    {
        /* lambda is to the right of the true multiplier. Get ready to
           search over the break points to the left by constructing the heaps
           for currently bound and free variables, and by fixing variables
           whose break points are to the right. */
        LOOP_OVER_UNFIXED ;
        {
            aj = a [j] ;
            if ( aj > NAPZERO )
            {
                const NAPFLOAT hij = (hiExists) ? hi [j] : NAPINF ;
                s = -hij/aj ;        /* lo break point */
                if ( s >= NAPZERO )     /* j is fixed */
                {
                    x [j] = hij ;
                    continue ;
                }
                else
                {
                    if ( loExists )
                    {
                        t = -lo [j]/aj ;    /* hi break point */
                        if ( t < NAPZERO )  /* j is bound */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = t ;
                        }
                        else             /* j is free */
                        {
                            a2sum += aj*aj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = s ;
                        }
                    }
                    else
                    {
                        a2sum += aj*aj ;
                        nfree++ ;
                        free_heap [nfree] = j ;
                        breakpts [j] = s ;
                    }
                }
            }
            else
            {
                const NAPFLOAT loj = (loExists) ? lo [j] : -NAPINF ;
                s = -loj/aj ;        /* lo break point */
                if ( s >= NAPZERO )     /* j is fixed */
                {
                    x [j] = loj ;
                    continue ;
                }
                else
                {
                    if ( hiExists )
                    {
                        t = -hi [j]/aj ;    /* hi break point */
                        if ( t < NAPZERO )  /* j is bound */
                        {
                            nbound++ ;
                            bound_heap [nbound] = j ;
                            breakpts [j] = t ;
                        }
                        else             /* j is free */
                        {
                            a2sum += aj*aj ;
                            nfree++ ;
                            free_heap [nfree] = j ;
                            breakpts [j] = s ;
                        }
                    }
                    else
                    {
                        a2sum += aj*aj ;
                        nfree++ ;
                        free_heap [nfree] = j ;
                        breakpts [j] = s ;
                    }
                }
            }
        }
        END_UNFIXED_LOOP ;

        /* build the free heap */
        napmaxheap_build (free_heap, breakpts, nfree) ;

        /* build the bound heap */
        napmaxheap_build (bound_heap, breakpts, nbound) ;

        /* d is positive, lambda is to the right of the true multiplier, and
           the break points are stored in a heap.  Search over the break points
           to the left until finding 0 slope */
        if ( nfree > 0 )
        {
            jfree = free_heap [1] ;
            maxfree = breakpts [jfree] ;
        }
        else maxfree = -NAPINF ;

        if ( nbound > 0 )
        {
            jb = bound_heap [1] ;
            maxbound = breakpts [jb] ;
        }
        else maxbound = -NAPINF ;

        while ( 1 )
        {
            new_break = MAX (maxfree, maxbound) ;
            t = slope - a2sum*(new_break - lambda) ;
            if ( (t >= NAPZERO) || (new_break <= -NAPINF) ) /* done */
            {
                if ( nfree ) lambda += slope/a2sum ;
                break ;
            }
            lambda = new_break ;
            slope = t ;

            /* update the heaps */
            while ( lambda == maxfree )
            {
                /* delete break point from heap */
                nfree = napmaxheap_delete (free_heap, breakpts, nfree) ;

                /* update a2sum */
                a2sum -= a [jfree]*a [jfree] ;

                /* get the smallest entry in heap */
                if ( nfree == 0 )
                {
                    maxfree = -NAPINF ;
                    if ( a2sum < NAPZERO ) a2sum = NAPZERO ;
                    break ;
                }
                else
                {
                    jfree = free_heap [1] ;
                    maxfree = breakpts [jfree] ;
                }
            }
            while ( lambda == maxbound )
            {
                /* delete break point from heap */
                nbound  = napmaxheap_delete(bound_heap, breakpts, nbound);

                /* compute new lo break point */
                aj = a [jb] ;
                if ( aj > NAPZERO )
                {
                    if ( hiExists ) s = -hi [jb]/aj ;
                    else            s = -NAPINF ;
                }
                else
                {
                    if ( loExists ) s = -lo [jb]/aj ;
                    else            s = -NAPINF ;
                }
                breakpts [jb] = s ;

                /* add new break point to free heap */
                nfree = napmaxheap_add (free_heap, breakpts, jb, nfree) ;

                /* get the smallest entry in free heap */
                jfree = free_heap [1] ;
                maxfree = breakpts [jfree] ;

                /* update a2sum and evaluate new break point */
                a2sum += aj*aj ;

                /* get the largest entry in bound heap */
                if ( nbound == 0 ) maxbound = -NAPINF ;
                else
                {
                    jb = bound_heap [1] ;
                    maxbound = breakpts [jb] ;
                }
            }
        }
    }

    /* evaluate the least squares solution */
    LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
        t = -lambda*a [j] ;
        if ( loExists && (t < lo [j]) )
        {
            t = lo [j] ;
        }
        else if ( hiExists && (t > hi [j]) )
        {
            t = hi [j] ;
        }
        x [j] = t ;
    END_LOOP ;
}

/*  =========================================================================
    === napsolution1 ========================================================
    =========================================================================
    d is positive and the optimal dual solution lambda has been determined.
    Evaluate the optimal primal solution. Sets variables in free heap and
    bound heap to optimal values. Assumes napsearch has been called.
    =========================================================================*/

PRIVATE void napsolution1
(
    NAPFLOAT        *x,  /* size n. solution (output) */
    NAPFLOAT const  *y,  /* size n. linear term in objective function */
    NAPFLOAT const  *d,  /* size n, diagonal of objective Hessian */
    NAPFLOAT const  *a,  /* size n, linear constraint vector */
    NAPFLOAT const *lo, /* size n, lower bounds on x */
    NAPFLOAT const *hi, /* size n, upper bounds on x */
    NAPFLOAT    lambda, /* optimal multiplier */
    NAPFLOAT     slope, /* slope of dual function determines search direction */
    NAPINT   const *kf,/* size n, known free variables */
    NAPINT         nkf, /* number of known free variables */
    NAPINT  *free_heap,
    NAPINT *bound_heap,
    NAPINT      n_free,
    NAPINT     n_bound,
    int const d_is_one
)
{
    NAPINT i ;
    NAPFLOAT const Lambda = lambda ;

    /* set variables in bound heap */
    for (i = 1; i <= n_bound; i++)
    {
        NAPINT j = bound_heap [i] ;
        if ( a [j] > 0 )
        {
            if ( slope < NAPZERO ) x [j] = lo [j] ; /* searching left */
            else                   x [j] = hi [j] ;
        }
        else
        {
            if ( slope < NAPZERO ) x [j] = hi [j] ; /* searching left */
            else                   x [j] = lo [j] ;
        }
    }

    if ( d_is_one )
    {
        /* set variables in free heap */
        for (i = 1; i <= n_free; i++)
        {
            NAPINT j = free_heap [i] ;
            x [j] = y [j] - Lambda*a [j] ;
        }
        /* set additional free variables */
        for (i = 0; i < nkf; i++)
        {
            NAPINT j = kf [i] ;
            x [j] = y [j] - Lambda*a [j] ;
        }
    }
    else
    {
        /* set variables in free heap */
        for (i = 1; i <= n_free; i++)
        {
            NAPINT j = free_heap [i] ;
            x [j] = (y [j] - Lambda*a [j])/d [j] ;
        }
        for (i = 0; i < nkf; i++)
        {
            NAPINT j = kf [i] ;
            x [j] = (y [j] - Lambda*a [j])/d [j] ;
        }
    }
}

/* ========================================================================== */
/* === nap_infeasible ======================================================= */
/* ========================================================================== */

/* The problem is infeasible; final wrapup */

PRIVATE void nap_infeasible
(
    NAPFLOAT        *x, /* size n. solution (output) */
    NAPFLOAT const  *a, /* size n. linear constraint vector */
    NAPFLOAT const *lo, /* size n. lower bounds for x */
    NAPFLOAT const *hi, /* size n. upper bounds for x */
    NAPINT         *uf, /* size n, list of unfixed variables */
    NAPINT         nuf, /* number of unfixed variables */
    NAPFLOAT     minax,
    NAPFLOAT     maxax,
    NAPFLOAT       blo, /* lower bound for a'x */
    NAPFLOAT       bhi  /* upper bound for a'x */
)
{
    NAPINT k ;

    /* return x that minimizes |a'x-b| */
    if ( minax > bhi )
    {
        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            if ( a [j] > NAPZERO ) x [j] = lo [j] ;
            else                   x [j] = hi [j] ;
        END_LOOP
    }
    else if ( maxax < blo )
    {
        LOOP_OVER_UNFIXED_NO_UF_UPDATE ;
            if ( a [j] > NAPZERO ) x [j] = hi [j] ;
            else                   x [j] = lo [j] ;
        END_LOOP
    }
}

/* ========================================================================== */
/* === nap_work ============================================================= */
/* ========================================================================== */

/* allocate NAPFLOAT workspace */

PRIVATE int nap_work
(
    NAPINT  const      n,
    NAPFLOAT      *xWork,     /* user-provide workspace */
    NAPFLOAT       **xw2,     /* return malloc'ed space */

    /* the 6 work arrays, each of size n */
    NAPFLOAT        **ad,
    NAPFLOAT        **ay,
    NAPFLOAT     **br_hi,
    NAPFLOAT     **br_lo,
    NAPFLOAT  **breakpts,
    NAPFLOAT **breaknext
)
{
    NAPFLOAT *work ;

    /* determine how many workspaces to allocate */
    int m, status ;

    status = NAPHEAP_STATUS_OK ;
    if ( xWork == NULL )
    {
        m = (ad != NULL) + (ay != NULL) + (br_hi != NULL) +
            (br_hi != NULL) + (breakpts != NULL) + (breaknext != NULL) ;
        /* n will not be zero at this point */
        (*xw2) = (NAPFLOAT *) napheap_malloc (&status, MAX(m*n,1),
                                              sizeof (NAPFLOAT)) ;
        if ( status == NAPHEAP_STATUS_OUT_OF_MEMORY )
        {
            return (status) ;
        }
        work = (*xw2) ;
    }
    else
    {
        /* use the user-provided workspace */
        work = xWork ;
        (*xw2) = NULL ;
    }

    /* allocate each array.  Each array is size n */
    if (breaknext != NULL)
    {
        (*breaknext) = work ;   work += n ;
    }
    if (breakpts != NULL)
    {
        (*breakpts) = work ;    work += n ;
    }
    if (ad != NULL)
    {
        (*ad) = work ;          work += n ;
    }
    if (ay != NULL)
    {
        (*ay) = work ;          work += n ;
    }
    if (br_hi != NULL)
    {
        (*br_hi) = work ;       work += n ;
    }
    if (br_lo != NULL)
    {
        (*br_lo) = work ;       work += n ;
    }

    return (status) ;
}

/* =========================================================================
   === NAPdot ==============================================================
   =========================================================================
   Compute dot product of x and y
   ========================================================================= */
PRIVATE NAPFLOAT nap_dot
(
    const NAPFLOAT *x, /* first vector */
    const NAPFLOAT *y, /* second vector */
    const NAPINT    n  /* length of vectors */
)
{
    NAPINT j, n5 ;
    NAPFLOAT t ;
    t = NAPZERO ;      /* initialize t */
    n5 = n % 5 ;        /* n5 = n mod 5 */
    for (j = 0; j < n5; j++) t += x [j]*y [j] ;
    for (; j < n; j += 5)
    {
        t += x [j]*y[j] + x [j+1]*y [j+1] + x [j+2]*y [j+2]
                        + x [j+3]*y [j+3] + x [j+4]*y [j+4] ;
    }
    return (t) ;        /* return x dot y */
}

/* construct the minheap functions */
#define CONSTRUCT_MINHEAP_FUNCTIONS
#include "napminmaxheap.c"

/* construct the maxheap functions */
#define CONSTRUCT_MAXHEAP_FUNCTIONS
#include "napminmaxheap.c"
