#ifndef _SNOPT_H
#define _SNOPT_H

#if defined (D64)
#define cint  int64_t
#else
#define cint  int
#endif

#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
//#include "iter.h"

typedef cint /* Unknown procedure type */ (*U_fp)();

typedef void (*snObjectiveFunc)
(
 cint   *mode,
 cint   *nnObj,
 double *x,
 double *fObj,
 double *gObj,
 cint   *nState,
 char   *cu,
 cint   *lencu,
 double *iu,
 cint   *leniu,
 double *ru,
 cint   *lenru
);

typedef void (*snConstraintFunc)
(
 cint   *mode,
 cint   *nnCon,
 cint   *nnJac,
 cint   *negCon,
 double *x,
 double *fCon,
 double *gCon,
 cint   *nState,
 char   *cu,
 cint   *lencu,
 double *iu,
 cint   *leniu,
 double *ru,
 cint   *lenru
);

typedef struct {
  cint   n;
  cint   m;
  cint   ne;
  cint   negCon;
  cint   nnCon;
  cint   nnObj;
  cint   nnJac;

} snDimension;

typedef struct {
  /* Printing */
  cint    major_print_level;
  cint    minor_print_level;
  char*   print_file_name;
  char*   sumry_file_name;
  cint    print_frequency;
  cint   summary_frequency;
  cint    solution_printed;
  cint    options_print_mode;

  /* Convergence Tolerances */
  double  major_feasibility_tolerance;
  double  major_optimality_tolerance;
  double  minor_feasibility_tolerance;
  double  minor_optimality_tolerance;

  /* Derivative checking */
  cint    verify_level;
  cint    start_obj_check_column;
  cint    stop_obj_check_column;
  cint    start_con_check_column;
  cint    stop_con_check_column;

  /* Scaling */
  cint    scale;
  double  scale_tolerance;
  cint    scale_print;

  /* Other Tolerances */
  double  crash_tolerance;
  double  linesearch_tolerance;
  double  LU_factor_tolerance;
  double  LU_update_tolerance;
  double  LU_singularity_tolerance;
  double  pivot_tolerance;

  /* QP subproblems */
  cint    crash_mode;
  double  elastic_weight;
  cint    iterations_limit;
  cint    partial_price;

  /* SQP method */
  cint    major_iterations_limit;
  cint    minor_iterations_limit;
  double  major_step_limit;
  cint    superbasics_limit;
  cint    reduced_Hessian_dimension;
  cint    derivative_level;
  cint    linesearch_mode;
  double  function_precision;
  double  difference_interval;
  double  central_difference_interval;
  double  violation_limit;
  double  unbounded_step_size;
  double  unbounded_objective;

  /* Hessian approximation */
  cint    hessian_memory_mode;
  cint    hessian_frequency;
  cint    hessian_updates;
  cint    hessian_flush;

  /* Frequencies */
  cint    check_frequency;
  cint    expand_frequency;
  cint    factorization_frequency;
  cint    save_frequency;

  /* Stuff        */

  double  objective_add;
  cint    start_mode;
  double  infinity;
  char   *ProblemName;

} snOption;

typedef struct {

  cint    num_major_iterations;
  cint    num_minor_iterations;
  cint    num_constraint_function_evals;
  cint    num_objective_function_evals;
  cint    num_superbasics;
  cint    num_degenerate_steps;
  cint    num_infeasibilities;

  double  max_primal_infeasibility;
  cint    i_max_primal_infeasibility;
  double  max_dual_infeasibility;
  cint    i_max_dual_infeasibility;
  double  max_scaled_primal_infeasibility;
  cint    i_max_scaled_primal_infeasibility;
  double  max_scaled_dual_infeasibility;
  double  i_max_scaled_dual_infeasibility;

  double  norm_scaled_solution;
  double  norm_solution;
  double  norm_scaled_multipliers;
  double  norm_multipliers;

  double  penalty;
  double  objective_value;
  double  linear_objective_value;
  double  nonlinear_objective_value;
  double  sum_infeasibilities;
  double  scaled_merit;
  double  elastic_weight;
  double  max_nonlinear_violation;

} snStats;

typedef struct {
  cint    print_file_unit;
  cint    sumry_file_unit;

  cint    length_rw;
  double *rw;

  cint    length_iw;
  cint   *iw;

  cint    length_cw;
  char   *cw;

  double *Jcol;
  cint   *indJ;
  cint   *locJ;

  double *bl;
  double *bu;
  cint   *hs;
  double *xs;
  double *pi;
  double *rc;

  snDimension dimension;
  snOption    option;
  snStats     stats;

  cint        linear_objective_row;
  cint        solve_mode;
  cint        exit_feasibility_mode;

  snConstraintFunc  constraint_func;
  snObjectiveFunc   objective_func;
  void*             func_data;

  cint        solve_status;
  cint        set_flags;

  /* error handling */
  cint    error;
  char*   error_msg;
  cint    error_msg_len;   /* length of message alloc'd (include \0 ) */

} snProblem;

extern cint snlog_();
extern cint snlog2_();
extern cint sqlog_ ();
extern cint snstop_();

/* Set functions */
cint   snSetObjectiveFunction        ( snProblem* prob, snObjectiveFunc  func );
cint   snSetConstraintFunction       ( snProblem* prob, snConstraintFunc func );
cint   snSetObjectiveAdd             ( snProblem* prob, double objective_add );
cint   snSetPrintFileName            ( snProblem* prob, char*  print_file_name );
cint   snSetSummaryFileName          ( snProblem* prob, char*  sumry_file_name );

/* Set functions assigning numeric arrays */
cint   snSetNonzero             ( snProblem* prob, cint nz , double Jcol , cint   indJ  );
cint   snSetNonzeroColumnPointer( snProblem* prob, cint nz , cint   locJ                );
cint   snSetVariable            ( snProblem* prob, cint var, cint   hs   , double xs    );
cint   snSetConstracint         ( snProblem* prob, cint con, cint   hs   , double xs    );
cint   snSetVariableBounds      ( snProblem* prob, cint var, double lower, double upper );
cint   snSetConstraintBounds    ( snProblem* prob, cint con, double lower, double upper );
cint   snSetMultiplier          ( snProblem* prob, cint con, double pi                  );

/* Get functions returning scalars */
double snGetMajorOptimalityTolerance      ( snProblem* prob );
double snGetMajorFeasibilityTolerance     ( snProblem* prob );
double snGetObjectiveAdd                  ( snProblem* prob );
cint   snGetNumNonlinearConstraints       ( snProblem* prob );
cint   snGetNumNonzeros                   ( snProblem* prob );
cint   snGetNumVariables                  ( snProblem* prob );
cint   snGetNumConstraints                ( snProblem* prob );
cint   snGetNumNonlinearObjectiveVariables( snProblem* prob );
cint   snGetNumNonlinearJacobianVariables ( snProblem* prob );
cint   snGetSolveStatus                   ( snProblem* prob );

/* Get functions returning pointers */
double *snGetNonzeroValues               ( snProblem* prob );
cint   *snGetNonzeroRowIndices           ( snProblem* prob );
cint   *snGetNonzeroColumnPointers       ( snProblem* prob );
double *snGetVariables                   ( snProblem* prob );
double *snGetConstraints                 ( snProblem* prob );
double *snGetConstraintUpperBounds       ( snProblem* prob );
double *snGetConstraintLowerBounds       ( snProblem* prob );
double *snGetVariableUpperBounds         ( snProblem* prob );
double *snGetVariableLowerBounds         ( snProblem* prob );
double *snGetMultipliers                 ( snProblem* prob );
cint   *snGetVariableBasisEligibilities  ( snProblem* prob );
cint   *snGetConstraintBasisEligibilities( snProblem* prob );

/* Get functions returning elements of arrays */
double  snGetNonzeroValue              ( snProblem* prob, cint nz  );
cint    snGetNonzeroRowIndex           ( snProblem* prob, cint nz  );
cint    snGetNonzeroColumnPointer      ( snProblem* prob, cint col );
double  snGetVariable                  ( snProblem* prob, cint var );
double  snGetConstracint               ( snProblem* prob, cint con );
double  snGetConstaintUpperBound       ( snProblem* prob, cint con );
double  snGetConstaintLowerBound       ( snProblem* prob, cint con );
double  snGetVariableUpperBound        ( snProblem* prob, cint var );
double  snGetVariableLowerBound        ( snProblem* prob, cint var );
double  snGetMultiplier                ( snProblem* prob, cint con );
cint    snGetVariableBasisEligibility  ( snProblem* prob, cint var );
cint    snGetConstraintBasisEligibility( snProblem* prob, cint con );

/* Get function returning times */
float   snGetCpuTime                   ( void );

/* Get functions returning integer solution statistics */
cint    snGetNumMinorIterations           ( snProblem* prob );
cint    snGetNumMajorIterations           ( snProblem* prob );
cint    snGetNumObjectiveFunctionEvals    ( snProblem* prob );
cint    snGetNumConstraintFunctionEvals   ( snProblem* prob );
cint    snGetNumSuperBasicVariables       ( snProblem* prob );
cint    snGetNumDegenerateSteps           ( snProblem* prob );
cint    snGetNumInfeasibleConstraints     ( snProblem* prob );
cint    snGetIMaxScaledPrimalInfeasibility( snProblem* prob );
cint    snGetIMaxScaledDualInfeasibility  ( snProblem* prob );
cint    snGetIMaxPrimalInfeasibility      ( snProblem* prob );
cint    snGetIMaxDualInfeasibility        ( snProblem* prob );

/* Get functions returning double solution statistics */
double  snGetNormScaledSolution          ( snProblem* prob );
double  snGetNormSolution                ( snProblem* prob );
double  snGetNormScaledMultipliers       ( snProblem* prob );
double  snGetNormMultipliers             ( snProblem* prob );
double  snGetPenalty                     ( snProblem* prob );
double  snGetObjectiveValue              ( snProblem* prob );
double  snGetLinearObjectiveValue        ( snProblem* prob );
double  snGetNonlinearObjectiveValue     ( snProblem* prob );
double  snGetSumInfeasibilities          ( snProblem* prob );
double  snGetMaxScaledPrimalInfeasibility( snProblem* prob );
double  snGetMaxScaledDualInfeasibility  ( snProblem* prob );
double  snGetMaxPrimalInfeasibility      ( snProblem* prob );
double  snGetMaxDualInfeasibility        ( snProblem* prob );

/* error handling */
cint    snGetError      ( snProblem* prob , char** error_msg );
void    snClearLastError( snProblem* prob );
void    snSetError      ( snProblem* prob , cint type , const char* error_msg );
cint    snCheck         ( snProblem* prob );

/* Principal routines */
cint snSolve ( snProblem* prob );
cint snDelete( snProblem* prob );
cint snInit  ( snProblem* prob ,
	      cint      variables,
	      cint      constraints,
	      cint      nonzeros,
	      cint      jacobian_nonzeros,
	      cint      nonlinear_constraints,
	      cint      nonlinear_objective_variables,
	      cint      nonlinear_jacobian_variables ,
	      cint      linear_objective_row,
              char      *print_file_name,
              char      *summary_file_name );

/* boolean */
#define SN_TRUE  1
#define SN_FALSE 0

/* error codes */
#define SN_ERROR                 0
#define SN_OK                    1
#define SN_FILE_ERROR            2  /* file error */
#define SN_PROBLEM_UNINITIALIZED 3
#define SN_PROBLEM_UNSOLVED      4

/* basis eligibility (hs) values */
#define SN_BASIS_COLD_ELIGIBLE_0   0
#define SN_BASIS_COLD_ELIGIBLE_1   1
#define SN_BASIS_IGNORE            2
#define SN_BASIS_COLD_ELIGIBLE_3   3
#define SN_BASIS_LOWER_BOUND       4
#define SN_BASIS_UPPER_BOUND       5

/* bits for set_flags */
#define SN_BIT_MAJOR_FEASIBILITY_TOLERANCE (1 << 0)
#define SN_BIT_MINOR_FEASIBILITY_TOLERANCE (1 << 1)
#define SN_BIT_MAJOR_OPTIMALITY_TOLERANCE  (1 << 2)
#define SN_BIT_MINOR_OPTIMALITY_TOLERANCE  (1 << 3)
#define SN_BIT_SOLVED                      (1 << 4)

/* "Normal" result conditions for snSolve() */
#define SN_SOLUTION_FOUND                      1
#define SN_INFEASIBLE                          2
#define SN_UNBOUNDED                           3
#define SN_VIOLATION_LIMIT_EXCEEDED            4
#define SN_MINOR_ITERATION_LIMIT_EXCEEDED      5
#define SN_MAJOR_ITERATION_LIMIT_EXCEEDED      6
#define SN_ACCURACY_NOT_ACHIEVED               7
#define SN_SUPERBASICS_LIMIT_EXCEEDED          8
#define SN_POINT_CANNOT_BE_IMPROVED            9
#define SN_CANNOT_SATISFY_GENERAL_CONSTRAINTS 10
#define SN_SINGULAR_BASIS                     11

/* "Error" result conditions for snSolve() */

#ifndef NULL
#define NULL 0L
#endif

#endif
