/* ========================================================================== */
/* === Include/napheap.h ==================================================== */
/* ========================================================================== */

/* include file for user programs that use napheap */

#ifndef NAPHEAP_H
#define NAPHEAP_H

#include "SuiteOPTconfig.h"

#define NAPFLOAT SuiteOPTfloat
#define NAPINT SuiteOPTint

/* infinite float */
#define NAPINF SuiteOPTinf

#define FALSE SuiteOPTfalse
#define TRUE SuiteOPTtrue

#define NAPZERO ((NAPFLOAT) 0)

#if 0
/* -- The following part of the original NAPHEAP make file is replaced    -- */
/* -- above by SuiteOPTconfig.h.                                          -- */
#include <limits.h>
#include <float.h>
#include <math.h>
#include <stdlib.h>

/* -------------------------------------------------------------------------- */
/* NAPHEAP_INT: the default integer for napheap */
/* -------------------------------------------------------------------------- */

/* NAPHEAP_INT can be defined at compile time (e.g. -DNAPHEAP_INT=long).
   For a MATLAB mexFunction, NAPHEAP_INT is always mwSignedIndex, which is
   32 bits on a 32 bit MATLAB, and 64 bits on a 64 bit MATLAB.  Most versions
   of MATLAB are now 64 bits.

   To change the integer definition, do not edit this file.  Edit the
   NAPINT string in Lib/napheap.mk instead, and use -DNAPHEAP_INT=long
   or -DNAPHEAP_INT='long long' or whatever you wish.  If you do this, you
   will need to ensure that your own source code that calls napheap is
   compiled with the same definition of NAPHEAP_INT.
*/

#ifdef MATLAB_MEX_FILE
#include "mex.h"
#define NAPHEAP_INT mwSignedIndex
#else
#ifndef NAPHEAP_INT
#define NAPHEAP_INT int
#endif
#endif

/* -------------------------------------------------------------------------- */
/* NAPHEAP_INF: the notion of infinity used by napheap */
/* -------------------------------------------------------------------------- */

/* ANSI C99 has a clean definition of IEEE infinity, defined in <math.h>.
   MATLAB has this as well.  With the ANSI (C90) version of C, there is no
   well-defined infinity, so DBL_MAX is used instead.

   You can override these defaults and define your own version of infinity
   with (for example):

   cc -ansi -DNAPHEAP_INF=1e200 napheap.c ...

   To do this, edit the OPTFLAGS string in Lib/napheap.mk.
*/

#ifndef NAPHEAP_INF
#ifdef INFINITY
/* ANSI C99 (gcc -std=c99) */
#define NAPHEAP_INF INFINITY
#else
/* ANSI C90 (gcc -ansi) */
#define NAPHEAP_INF DBL_MAX
#endif
#endif

#endif

/* -------------------------------------------------------------------------- */
/* status return value from napheap */
/* -------------------------------------------------------------------------- */

#define NAPHEAP_STATUS_OK                   (0)
#define NAPHEAP_STATUS_INFEASIBLE           (300)
#define NAPHEAP_STATUS_UNBOUNDED            (301)
#define NAPHEAP_STATUS_OUT_OF_MEMORY        (302)
#define NAPHEAP_STATUS_INVALID_N            (303)
#define NAPHEAP_STATUS_INVALID_BOUNDS       (304)
#define NAPHEAP_STATUS_INVALID_B            (305)
#define NAPHEAP_STATUS_INVALID_D            (306)
#define NAPHEAP_STATUS_INVALID_NEWTON       (307)
#define NAPHEAP_STATUS_CONFLICTING_PARM_D   (308)
#define NAPHEAP_STATUS_MISSING_PARM         (309)
#define NAPHEAP_STATUS_MISSING_STAT         (310)

#define NAPHEAP_START_MESSAGES              (300)
#define NAPHEAP_END_MESSAGES                (399)

/* -------------------------------------------------------------------------- */
/* napheap version information */
/* -------------------------------------------------------------------------- */
#define NAPHEAP_DATE "October 30, 2019"
#define NAPHEAP_MAIN_VERSION 3
#define NAPHEAP_SUB_VERSION 0
#define NAPHEAP_SUBSUB_VERSION 0

/* -------------------------------------------------------------------------- */
/* user-controllable parameters */
/* -------------------------------------------------------------------------- */

typedef struct NAPparm_struct
{
    /* T => print status of run */
    int PrintStatus ;

    /* T => print statistics of the run */
    int PrintStat ;

    /* T => print the parameters */
    int PrintParm ;

    /* T => use arrays from a prior run */
    int use_prior_data ;

    /* T => do not free arrays from current run, save them in napheap
            input structure napdata; this is useful when solving the
            same problem but with a different linear cost vector y */
    int return_data ;

    /* F => treat input argument lo as -infinity */
    int loExists ;

    /* F => treat input argument hi as +infinity */
    int hiExists ;

    /* F => no linear constraints bl <= a'x <= bu */
    int Aexists ;

    /* T => diagonal of objective Hessian is all positive, and the
            MATLAB expression all(d>0) is assumed to be true.
       F => there could be zeros on the diagonal of the Hessian */
    int d_is_pos ;

    /* T => diagonal of objective Hessian is zero.
            Note: The d argument of napheap is ignored. It could be NULL
       F => there could be nonzeros on the diagonal of the Hessian */
    int d_is_zero ;

    /* T => diagonal of objective Hessian is identically 1.
            Note: The d argument of napheap is ignored. It could be NULL */
    int d_is_one ;

    /* Upper bound on the number of Newton or variable fixing iterations.
       After performing these K iterations, the code switches to the break
       point search. The Newton algorithm also switches to the breakpoint
       search if two iterates are generated on opposite sides of the root. */
    int K ;

    /* T => use the Newton to update lambda, switch to the break point
       search either at iteration K or at the first time that two
       Newton iterates lie on opposite side of the root (whichever
       happens first)
       F => use K iterations of the variable fixing algorithm before
       switching to a breakpoint search */
    int newton ;

    /* An ordinary Newton iteration often converges monotonically to the
       root. Hence, the Newton iterates are scaled by a factor greater than 1
       in an effort to produce an iterate on the opposite side of the root.
       When such an iterate is generated, the algorithm switches to a
       breakpoint search. The scaled iteration is given by
                    
       lambda_new = lambda_old - newton_scale*L'(lambda_old)/L''(lambda_old) */

    NAPFLOAT newton_scale ;

    /* To combat the effect of rounding errors, recompute a2sum whenever
       a2sum <= decay*a2max, the maximum a2sum encountered */
    double decay ;

     /* T => perform an iterative refinement step to improve solution accurary
        F => no refinement */
    int refine ;

    /* The solution is refined if |a'x - b| > err (only if refine is true) */
    NAPFLOAT err ;

    /* Check the input parameters for dj < 0 or hij < loj or bhi < blo */
    int check ;

} NAPparm ;

/* -------------------------------------------------------------------------- */
/* statistics returned to the user */
/* -------------------------------------------------------------------------- */

typedef struct NAPstat_struct
{
    NAPINT     nkf ;   /* number of known free variables */
    NAPINT   nfree ;   /* number of free variables in initial heap */
    NAPINT  nbound ;   /* number of bound variables in initial heap */
    NAPINT   nbrks ;   /* number break points to reach initial solution */
    NAPINT nrefine ;   /* number of break points during refinement */
    NAPINT nvarfix ;   /* number of variable fixing iterations */
    NAPINT nnewton ;   /* number of Newton iterations performed */
    NAPINT nsecant ;   /* number of secant steps performed */

    /* for error reporting */
    int     status ;   /* returned status from napheap */
    NAPINT  kerror ;   /* invalid n, or index where error found */
    NAPFLOAT lobad ;   /* bad value of lo, if any */
    NAPFLOAT hibad ;   /* bad value of hi, if any */
    NAPFLOAT  dbad ;   /* bad value of d, if any */

} NAPstat ;

/* -------------------------------------------------------------------------- */
/* data structure for input and output to napheap */
/* -------------------------------------------------------------------------- */

typedef struct NAPdata_struc
{   
    NAPFLOAT       *x  ; /* size n. solution (output) */
    NAPFLOAT    lambda ; /* input: starting multiplier guess if parameter
                            use_lambda = TRUE, otherwise ignored on input.
                            output: final multiplier (scalar) */
    NAPINT           n ; /* problem dimension */
    NAPFLOAT        *y ; /* size n. linear term in objective function */
    NAPFLOAT        *d ; /* size n. diagonal of objective Hessian */
    NAPFLOAT        *a ; /* size n. linear constraint vector */
    NAPFLOAT       blo ; /* lower bound for a'x */
    NAPFLOAT       bhi ; /* upper bound for a'x */
    NAPFLOAT       *lo ; /* size n. lower bounds for x */
    NAPFLOAT       *hi ; /* size n. upper bounds for x */
    NAPstat      *Stat ; /* structure for statistics */
    NAPparm      *Parm ; /* structure for parameters */
    NAPFLOAT    *xWork ; /* 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). */
    NAPINT      *iWork ; /* NULL => let code allocate NAPINT memory
                            otherwise use iWork for NAPINT memory (4*n+1).*/

    /* the following are used internally when the code allocates memory */
    NAPFLOAT     *x_created ;
    NAPFLOAT     *y_created ;
    NAPFLOAT *xWork_created ;
    NAPINT   *iWork_created ;
    /* sum ak*ak/dk, k = 1:n, from a previous run */
    NAPFLOAT         akakdk ;
} NAPdata ;

/* -------------------------------------------------------------------------- */
/* prototypes for user-callable functions */
/* -------------------------------------------------------------------------- */

int napheap  /* napheap_print_status (napdata) gives the status of the run */
(
    NAPdata *napdata
) ;

void * napheap_malloc
(
    int *status,
    NAPINT    n,
    int    size
) ;

void napheap_free
(
    void * p
) ;

NAPdata * napheap_setup (void) ;

void napheap_terminate
(
    NAPdata **DataHandle
) ;

/* set default parameter values */
void napheap_default
(
    NAPparm *Parm
) ;

void napheap_print_status
(
    NAPdata *Data
) ;

/* print the napheap statistics */
void napheap_print_stat
(
    NAPdata *Data
) ;

/* print the parameters */
void napheap_print_parm
(
    NAPdata *Data
) ;

/* estimate the napheap solution error */
NAPFLOAT napheap_check /* returns largest of the 3 error values */
(
    NAPFLOAT     *errb, /* relative error in b (only return if not NULL) */
    NAPFLOAT     *errB, /* relative error in bounds (only return if not NULL) */
    NAPFLOAT     *erry, /* relative error in y (only return if not NULL) */
    NAPdata   *napdata
) ;

#endif
