/**
 * @brief Convex Quadratic Programming library
 *
 * From:
 * http://ra.uni-trier.de/~huebner/software.html
 *
 * ----------------------------------------------------------------------
 *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * ----------------------------------------------------------------------
 *
 * @author Ewgenij Hübner
 *
 * $$
 */

#ifndef GSL_CQP_H
#define GSL_CQP_H

#include <gsl/gsl_matrix.h>
#include <gsl/gsl_vector.h>

//#ifdef __cplusplus
//# define __BEGIN_DECLS extern "C" {
//# define __END_DECLS }
//#else
//# define __BEGIN_DECLS /* empty */
//# define __END_DECLS /* empty */
//#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    /* objective function: 0.5*(x^t)Qx+(q^t)x */
    gsl_matrix *Q;
    gsl_vector *q;

    /* constraints: Ax=b; Cx>=d */
    const gsl_matrix *A;
    const gsl_vector *b;
    gsl_matrix *C;
    gsl_vector *d;
} gsl_cqp_data;

typedef struct {
    const char *name;
    size_t size;
    int (*alloc)(void *state, size_t n, size_t me, size_t mi);
    int (*set)(void *state, const gsl_cqp_data *cqp, gsl_vector *x,
               gsl_vector *y, gsl_vector *z, double *gap,
               double *residuals_norm, double *data_norm, double *inf_barrier,
               double *inf_barrier_min);
    int (*iterate)(void *state, const gsl_cqp_data *cqp, gsl_vector *x,
                   gsl_vector *y, gsl_vector *z, double *gap,
                   double *residuals_norm, double *inf_barrier,
                   double *inf_barrier_min);

    /*  int (*restart) (void *state); */
    void (*free)(void *state);
} gsl_cqpminimizer_type;

typedef struct {
    const gsl_cqpminimizer_type *type;

    gsl_cqp_data *cqp;
    gsl_vector *x;
    /* Lagrange-multipliers */
    gsl_vector *y; /*corresponding to Ax=b */
    gsl_vector *z; /*corresponding to CX>=d */

    double gap;
    double residuals_norm;
    double data_norm;
    double quantity_of_infeasibility;
    double quantity_of_infeasibility_min;

    void *state;
} gsl_cqpminimizer;

gsl_cqpminimizer *gsl_cqpminimizer_alloc(const gsl_cqpminimizer_type *T,
                                         size_t n, size_t me, size_t mi);
/*
int
gsl_cqpminimizer_set (gsl_cqpminimizer * minimizer, gsl_cqp_problem * cqp);
*/
int gsl_cqpminimizer_set(gsl_cqpminimizer *minimizer, gsl_cqp_data *cqp);

void gsl_cqpminimizer_free(gsl_cqpminimizer *minimizer);

const char *gsl_cqpminimizer_name(const gsl_cqpminimizer *minimizer);

int gsl_cqpminimizer_iterate(gsl_cqpminimizer *minimizer);

/*
int
gsl_cqpminimizer_restart(gsl_cqpminimizer *minimizer);
*/

gsl_vector *gsl_cqpminimizer_x(gsl_cqpminimizer *minimizer);

gsl_vector *gsl_cqpminimizer_lm_eq(gsl_cqpminimizer *minimizer);

gsl_vector *gsl_cqpminimizer_lm_ineq(gsl_cqpminimizer *minimizer);

double gsl_cqpminimizer_f(gsl_cqpminimizer *minimizer);

double gsl_cqpminimizer_gap(gsl_cqpminimizer *minimizer);

double gsl_cqpminimizer_residuals_norm(gsl_cqpminimizer *minimizer);

int gsl_cqpminimizer_test_convergence(gsl_cqpminimizer *minimizer,
                                      double eps_gap, double eps_residual);

int gsl_cqp_minimizer_test_infeasibility(gsl_cqpminimizer *minimizer,
                                         double eps_infeasible);

double gsl_cqpminimizer_minimum(gsl_cqpminimizer *minimizer);

GSL_VAR const gsl_cqpminimizer_type *gsl_cqpminimizer_mg_pdip;
/*GSL_VAR const gsl_cqpminimizer_type *gsl_cqpminimizer_pdip_mpc_eqc;*/

#ifdef __cplusplus
}
#endif

#endif
