幾個優化算法庫的簡單測試

最近心血來潮,對幾個優化算法庫進行了簡單測試,包括google ceres, dlib中的優化算法,ipopt, osqp, gsl中的最小化算法,簡單記錄一下。

本測試在ubuntu 18.04下完成,採用qt creator作爲開發環境。幾個庫的安裝都是通過apt直接安裝,只有osqp是下載源碼編譯的。編譯過程是linux下標準的configure, make, make install。

 

新建QT工程後設置頭文件路徑和鏈接庫路徑、鏈接庫如下:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += \
    osqp.c \
    dlib.cpp \
    main.cpp \
    ipopt.c \
    ceres.cpp \
    function.c \
    gsl_multimin.c

HEADERS += \
    fmincon.h

INCLUDEPATH += /home/praise/development/cpp/FinalLib/include/coin-or \
               /home/praise/development/cpp/FinalLib/include \
               /home/praise/development/cpp/FinalLib/include/osqp \
               /usr/include/eigen3

LIBS += -L/home/praise/development/cpp/FinalLib/lib \
        -lipopt -lopenblas \
        -lgsl -lgslcblas -lm \
        -losqp -ldlib \
        -lceres -lglog

 

從配置文件可以看出,總共涉及一個頭文件和7個c/c++源文件(不包括庫頭文件)。其中main.cpp和function.c分別是main函數和目標函數,其他幾個文件分別代表每個庫調用目標函數進行優化計算的適配代碼。所有文件的源代碼如下:

fmincon.h

#ifndef __fmincon__H
#define __fmincon__H

#include "IpStdCInterface.h"
#include "cblas.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>


/////////////////////////////////////////////
/* below is added for convinient */
struct MyUserData
{
    Index row;
    Index col;
    Number* ker;
    Number* Wm;
    Number* bs;
    Number* tt;
    Number* A_cond;
    Number* b_cond;
    Number alf;
};
/* above is added this time */
////////////////////////////////////////////

typedef Bool(*Eval_NLC_CB)(  // calc non linear constraints
    Index       n,     // number of x
    Number*     x,
    Bool        new_x,
    Index       m1,    // number of c
    Index       m2,    // number of ceq
    Number*     c,
    Number*     ceq,
    UserDataPtr user_data
    );

// this is the similar function as matlab
// return status of the solution
// the parameters are described below
enum ApplicationReturnStatus fmincon(
    Eval_F_CB obj_func,        // (in) pointer, the objective function of above form
    Index n_var,               // (in) integer, the number of components in x
    Number* x,                 // (in, out) vector, As Input: Starting point; As Output: Optimal solution
    Index m_lc,                // (in) integer, the number of components in linear inequalities, 0 if not exist
    Number* A,                 // (in) matrix, linear inequalities A*x ≤ b, NULL if not exist
    Number* b,                 // (in) vector, linear inequalities A*x ≤ b, NULL if not exist
    Index m_leqc,              // (in) integer, the number of components in linear equalities, 0 if not exist
    Number* Aeq,               // (in) matrix, linear equalities Aeq*x = beq, NULL if not exist
    Number* beq,               // (in) vector, linear equalities Aeq*x = beq, NULL if not exist
    Number* lb,                // (in) vector, lower bounds of x, lb <= x <= ub, NULL if not exist
    Number* ub,                // (in) vector, upper bounds of x, lb <= x <= ub, NULL if not exist
    Index m_nl,                // (in) integer, the number of non linear inequalities, 0 if not exist
    Index m_nleq,              // (in) integer, the number of non linear equalities, 0 if not exist
    Eval_NLC_CB nonlcon,       // (in) pointer, the non linear constraints function of above form, NULL if not exist
    Index m_opt,               // (in) integer, number of options, 0 if take default
    char*** options,            // (in) string pair to describe the options, the form is char[:][2][:], NULL if take default
    UserDataPtr user_data,     // (in) pointer, the parameters in objective functions, NULL if not exist
    Number *fval,               // (out) real, the optimized value of objective function
    FILE* output,               // (out) file pointer, write some info about calculation to the file
    Number* lambda,            // (out) vector, Lagrange multipliers at the solution, length = m_lc+mleqc+m_nl+m_nleq
    Number* grad,              // (out) vector, Gradient at the solution, length = n_var
    Number* hessian            // (out) matrix, Approximate Hessian, length = n_var*n_var
    );

extern Index m_n;
extern Index m_m1;

extern Index m_m2;
extern Index m_m3;
extern Index m_m4;

extern Index m_nonnegMatrix;
extern Number m_tol;
extern Number m_step;

extern Number *m_A;
extern Number *m_b;
extern Number *m_g_Ax;
extern Number *m_Aeq;
extern Number* m_beq;
extern Number *m_g_Aeqx;

extern Number* m_lb;
extern Number* m_ub;

extern Number* m_jac_g_c;
extern Number* m_jac_g_ceq;
extern Number* m_ci;
extern Number* m_ceqi;
extern Number* m_cij;
extern Number* m_ceqij;

extern Eval_F_CB m_func;
extern Eval_NLC_CB m_nonlcon;
extern FILE* m_debuglog;

extern struct MyUserData my_data;

void Init_UserData(Index n, Index m, struct MyUserData *user_data, const char *path);
Bool eval_f(Index n, Number* x, Bool new_x, Number* obj_value, UserDataPtr user_data);
Bool eval_grad_f_spec(Index n, Number* x, Bool new_x, Number* grad_f, UserDataPtr user_data);
Bool eval_g(Index n, Number* x, Bool new_x, Index m, Number* g, UserDataPtr user_data);
Bool eval_jac_g(Index n, Number* x, Bool new_x, Index m, Index nele_jac, Index* iRow, Index* jCol, Number* values, UserDataPtr user_data);
Bool eval_h_spec(Index n,Number* x,Bool new_x,Number obj_factor,Index m,Number* lambda,Bool new_lambda,Index nele_hess,Index* iRow,Index* jCol,Number* values,UserDataPtr user_data);

#endif

 

main.cpp

#include <stdio.h>
#include <iostream>

extern "C" {
    int Ipopt();
    int gsl_multimin();
    int osqp();
}

void dlib_test();
int ceres_test();

int main()
{
    clock_t start = clock();
    Ipopt();
    gsl_multimin();
    osqp();
    dlib_test();
    ceres_test();
    clock_t end = clock();
    double elapsed = (double)(end - start)/ CLOCKS_PER_SEC;
    std::cout << "algorithm used: " << elapsed << " seconds." << std::endl;
}

 

ceres.cpp

// time consume: 0.159     fun(x): 2959.16

extern "C" {
#include "fmincon.h"
}
#include "ceres/ceres.h"
#include "glog/logging.h"

class test_func : public ceres::FirstOrderFunction {
 public:
  virtual ~test_func() {}

  virtual bool Evaluate(const double* parameters,
                        double* cost,
                        double* gradient) const {
    eval_f(m_n, (double*)parameters, true, cost, &my_data);
    if (gradient != NULL) {
      eval_grad_f_spec(m_n, (double*)parameters, true, gradient, &my_data);
    }
    return true;
  }

  virtual int NumParameters() const { return 30; }
};

int ceres_test() {
  google::InitGoogleLogging("ceres_test");

  m_n = 30;
  m_m1 = 2;
  double parameters[30] = {
      0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
      0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
      0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
      0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
      0.99, 0.99, 0.99, 0.99, 0.99, 0.99
  };

  Init_UserData(m_n, m_m1, &my_data, "bs1.txt");

  ceres::GradientProblemSolver::Options options;
  options.minimizer_progress_to_stdout = true;

  ceres::GradientProblemSolver::Summary summary;
  ceres::GradientProblem problem(new test_func());
  ceres::Solve(options, problem, parameters, &summary);

  std::cout << summary.FullReport() << "\n";
  std::cout << "x: " << std::endl;
  for (int i = 0; i < 30; i++)
  {
      std::cout << parameters[i] <<  "\n";
  }
  double y = 0;
  eval_f(m_n, parameters, true, &y, &my_data);
  std::cout << "f: " << y << std::endl;
  return 0;
}

 

dlib.cpp


#include <dlib/optimization.h>
#include <iostream>
extern "C" {
#include "fmincon.h"
}


using namespace std;
using namespace dlib;

// ----------------------------------------------------------------------------------------

// In dlib, the general purpose solvers optimize functions that take a column
// vector as input and return a double.  So here we make a typedef for a
// variable length column vector of doubles.  This is the type we will use to
// represent the input to our objective functions which we will be minimizing.
typedef matrix<double,0,1> column_vector;

// ----------------------------------------------------------------------------------------
// Below we create a few functions.  When you get down into main() you will see that
// we can use the optimization algorithms to find the minimums of these functions.
// ----------------------------------------------------------------------------------------

double *x;
double test_func (const column_vector& m)
{
    for (int i = 0; i < m_n; i++)
    {
        x[i] = m(i);
    }
    double y;
    eval_f(m_n, x, true, &y, &my_data);
    return y;
}

// This is a helper function used while optimizing the function.
const column_vector test_func_derivative (const column_vector& m)
{
    for (int i = 0; i < m_n; i++)
    {
        x[i] = m(i);
    }

    column_vector res(m_n);
    double *grad = (double*)malloc(sizeof(double)*m_n);

    // now compute the gradient vector
    eval_grad_f_spec(m_n, x, true, grad, &my_data);

    for (int i = 0; i < m_n; i++)
    {
        res(i) = grad[i];
    }
    free(grad);
    return res;
}

// This function computes the Hessian matrix for the rosen() fuction.  This is
// the matrix of second derivatives.
matrix<double> test_func_hessian (const column_vector& m)
{
    for (int i = 0; i < m_n; i++)
    {
        x[i] = m(i);
    }

    matrix<double> res(m_n,m_n);
    int nele_hess = m_n * (m_n + 1) / 2;
    const double obj_factor = 1;
    double *lambda = (double*)malloc(sizeof(double)*m_m1);
    int *iRow = (int*)malloc(sizeof(int)*nele_hess);
    int *jCol = (int*)malloc(sizeof(int)*nele_hess);
    double *values = (double*)malloc(sizeof(double)*nele_hess);

    // now compute the second derivatives
    eval_h_spec(m_n,x,true,obj_factor,m_m1,lambda,true,
                nele_hess,iRow,jCol,values,&my_data);
    for (int i = 0; i < m_n; i++)
    {
        for (int j = 0; j <= i; j++)
        {
            int idx = (i + 1) * i / 2 + j;
            res(i, j) = res(j, i) = values[idx];
        }
    }


    free(lambda);
    free(iRow);
    free(jCol);
    free(values);
    return res;
}

// ----------------------------------------------------------------------------------------

class test_function
{
    /*
        This object is an example of what is known as a "function object" in C++.
        It is simply an object with an overloaded operator().  This means it can
        be used in a way that is similar to a normal C function.  The interesting
        thing about this sort of function is that it can have state.

        In this example, our test_function object contains a column_vector
        as its state and it computes the mean squared error between this
        stored column_vector and the arguments to its operator() function.
        This is a very simple function, however, in general you could compute
        any function you wanted here.  An example of a typical use would be
        to find the parameters of some regression function that minimized
        the mean squared error on a set of data.  In this case the arguments
        to the operator() function would be the parameters of your regression
        function.  You would loop over all your data samples and compute the output
        of the regression function for each data sample given the parameters and
        return a measure of the total error.   The dlib optimization functions
        could then be used to find the parameters that minimized the error.
    */
public:

    test_function (
        const column_vector& input
    )
    {
        target = input;
    }

    double operator() ( const column_vector& arg) const
    {
        // return the mean squared error between the target vector and the input vector
        return mean(squared(target-arg));
    }

private:
    column_vector target;
};

// ----------------------------------------------------------------------------------------

class rosen_model
{
    /*!
        This object is a "function model" which can be used with the
        find_min_trust_region() routine.
    !*/

public:
    typedef ::column_vector column_vector;
    typedef matrix<double> general_matrix;

    double operator() (
        const column_vector& x
    ) const
    {
        //return rosen(x);
        return test_func(x);
    }

    void get_derivative_and_hessian (
        const column_vector& x,
        column_vector& der,
        general_matrix& hess
    ) const
    {
        der = test_func_derivative(x);
        hess = test_func_hessian(x);
    }
};

// ----------------------------------------------------------------------------------------

void dlib_test()
{
    m_n = 30;
    m_m1 = 2;
    x = (double*)malloc(sizeof(double)*m_n);
    Init_UserData(m_n, m_m1, &my_data, "bs1.txt");
    try
    {
        // make a column vector of length 2
        column_vector starting_point(30);


        // Set the starting point to (4,8).  This is the point the optimization algorithm
        // will start out from and it will move it closer and closer to the function's
        // minimum point.   So generally you want to try and compute a good guess that is
        // somewhat near the actual optimum value.
        starting_point = 0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
                0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
                0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
                0.99, 0.99, 0.99, 0.99, 0.99, 0.99,
                0.99, 0.99, 0.99, 0.99, 0.99, 0.99;

        // The first example below finds the minimum of the rosen() function and uses the
        // analytical derivative computed by rosen_derivative().  Since it is very easy to
        // make a mistake while coding a function like rosen_derivative() it is a good idea
        // to compare your derivative function against a numerical approximation and see if
        // the results are similar.  If they are very different then you probably made a
        // mistake.  So the first thing we do is compare the results at a test point:
//        cout << "Difference between analytic derivative and numerical approximation of derivative: "
//              << length(derivative(test_func)(starting_point) - test_func_derivative(starting_point)) << endl;


        cout << "Find the minimum of the function()" << endl;
        // Now we use the find_min() function to find the minimum point.  The first argument
        // to this routine is the search strategy we want to use.  The second argument is the
        // stopping strategy.  Below I'm using the objective_delta_stop_strategy which just
        // says that the search should stop when the change in the function being optimized
        // is small enough.

        // The other arguments to find_min() are the function to be minimized, its derivative,
        // then the starting point, and the last is an acceptable minimum value of the rosen()
        // function.  That is, if the algorithm finds any inputs to rosen() that gives an output
        // value <= -1 then it will stop immediately.  Usually you supply a number smaller than
        // the actual global minimum.  So since the smallest output of the rosen function is 0
        // we just put -1 here which effectively causes this last argument to be disregarded.
// time consume: 0.111   fun(x): 2959.05
//        find_min(bfgs_search_strategy(),  // Use BFGS search algorithm
//                 objective_delta_stop_strategy(1e-7), // Stop when the change in rosen() is less than 1e-7
//                 test_func, test_func_derivative, starting_point, -1);
        // Once the function ends the starting_point vector will contain the optimum point
        // of (1,1).
//        cout << "solution:\n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;


        // Now let's try doing it again with a different starting point and the version
        // of find_min() that doesn't require you to supply a derivative function.
        // This version will compute a numerical approximation of the derivative since
        // we didn't supply one to it.
// time consume: 0.274   fun(x): 2959.05
//        find_min_using_approximate_derivatives(bfgs_search_strategy(),
//                                               objective_delta_stop_strategy(1e-7),
//                                               test_func, starting_point, -1);
        // Again the correct minimum point is found and stored in starting_point
//        cout << "solution:\n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;


        // Here we repeat the same thing as above but this time using the L-BFGS
        // algorithm.  L-BFGS is very similar to the BFGS algorithm, however, BFGS
        // uses O(N^2) memory where N is the size of the starting_point vector.
        // The L-BFGS algorithm however uses only O(N) memory.  So if you have a
        // function of a huge number of variables the L-BFGS algorithm is probably
        // a better choice.
// time consume: 0.239    fun(x): 2959.05
//        find_min(lbfgs_search_strategy(10),  // The 10 here is basically a measure of how much memory L-BFGS will use.
//                 objective_delta_stop_strategy(1e-7).be_verbose(),  // Adding be_verbose() causes a message to be
                                                                    // printed for each iteration of optimization.
//                 test_func, test_func_derivative, starting_point, -1);

//        cout << endl << "solution: \n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;

// time consume: 0.674    fun(x): 2959.05
//        find_min_using_approximate_derivatives(lbfgs_search_strategy(10),
//                                               objective_delta_stop_strategy(1e-7),
//                                               test_func, starting_point, -1);
//        cout << "solution: \n"<< starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;



        // dlib also supports solving functions subject to bounds constraints on
        // the variables.  So for example, if you wanted to find the minimizer
        // of the rosen function where both input variables were in the range
        // 0.1 to 0.8 you would do it like this:
// time consume: 0.150      fun(x): 2980.62
//        find_min_box_constrained(lbfgs_search_strategy(10),
//                                 objective_delta_stop_strategy(1e-7),
//                                 test_func, test_func_derivative, starting_point, 0, 100);
        // Here we put the same [0 100] range constraint on each variable, however, you
        // can put different bounds on each variable by passing in column vectors of
        // constraints for the last two arguments rather than scalars.

//        cout << endl << "constrained solution: \n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;

        // You can also use an approximate derivative like so:
// time consume: 0.224       fun(x): 2980.62
//        find_min_box_constrained(bfgs_search_strategy(),
//                                 objective_delta_stop_strategy(1e-7),
//                                 test_func, derivative(test_func), starting_point, 0, 100);
//        cout << endl << "constrained solution: \n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;




        // In many cases, it is useful if we also provide second derivative information
        // to the optimizers.  Two examples of how we can do that are shown below.
// time consume: 0.039       fun(x): 2959.05
        find_min(newton_search_strategy(test_func_hessian),
                 objective_delta_stop_strategy(1e-7),
                 test_func,
                 test_func_derivative,
                 starting_point,
                 -1);
        cout << "solution: \n"<< starting_point << endl;
        cout << "f: " << test_func(starting_point) << endl;

        // We can also use find_min_trust_region(), which is also a method which uses
        // second derivatives.  For some kinds of non-convex function it may be more
        // reliable than using a newton_search_strategy with find_min().
// time consume: 0.040       fun(x): 2959.05
        find_min_trust_region(objective_delta_stop_strategy(1e-7),
            rosen_model(),
            starting_point,
            10 // initial trust region radius
        );
        cout << "solution: \n"<< starting_point << endl;
        cout << "f: " << test_func(starting_point) << endl;




        // Now let's look at using the test_function object with the optimization
        // functions.
//        cout << "\nFind the minimum of the test_function" << endl;


        // This variable will be used as the target of the test_function.   So,
        // our simple test_function object will have a global minimum at the
        // point given by the target.  We will then use the optimization
        // routines to find this minimum value.

        // set the starting point far from the global minimum
// time consume: 0.314      fun(x): 2959.05
//        find_min_using_approximate_derivatives(bfgs_search_strategy(),
//                                               objective_delta_stop_strategy(1e-7),
//                                               rosen_model(), starting_point, -1);
        // At this point the correct value should be found and stored in starting_point
//        cout << "test_function solution:\n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;

        // Now let's try it again with the conjugate gradient algorithm.
// time consume: 1.336     fun(x):  2959.05
//        find_min_using_approximate_derivatives(cg_search_strategy(),
//                                               objective_delta_stop_strategy(1e-7),
//                                               rosen_model(), starting_point, -1);
//        cout << "test_function solution:\n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;


        // Finally, let's try the BOBYQA algorithm.  This is a technique specially
        // designed to minimize a function in the absence of derivative information.
        // Generally speaking, it is the method of choice if derivatives are not available.
//        find_min_bobyqa(rosen_model(), //test_function(target),
//                        starting_point,
//                        9,    // number of interpolation points
//                        uniform_matrix<double>(m_n,1, 0),  // lower bound constraint
//                        uniform_matrix<double>(m_n,1, 100),   // upper bound constraint
//                        10,    // initial trust region radius
//                        1e-6,  // stopping trust region radius
//                        100    // max number of objective function evaluations
//        );
//        cout << "test_function solution:\n" << starting_point << endl;
//        cout << "f: " << test_func(starting_point) << endl;
    }
    catch (std::exception& e)
    {
        cout << e.what() << endl;
    }
    free(x);
}

 

function.c

#include "fmincon.h"
#include <assert.h>

#define N_ROW 1050
#define N_COL 30

Index m_n;
Index m_m1;
Index m_m2;
Index m_m3;
Index m_m4;

Index m_nonnegMatrix;
Number m_tol;
Number m_step;

Number *m_A;
Number *m_b;
Number *m_g_Ax;
Number *m_Aeq;
Number* m_beq;
Number *m_g_Aeqx;

Number* m_lb;
Number* m_ub;

Number* m_jac_g_c;
Number* m_jac_g_ceq;
Number* m_ci;
Number* m_ceqi;
Number* m_cij;
Number* m_ceqij;

Eval_F_CB m_func;
Eval_NLC_CB m_nonlcon;
FILE* m_debuglog;

struct MyUserData my_data;

void Init_UserData(Index n, Index m, struct MyUserData *user_data, const char *path)
{
    m_debuglog = fopen("./testlog.txt", "a+");
//	fopen_s(&logfile, "log.txt", "a+");

    user_data->row = N_ROW;
    user_data->col = N_COL;
    user_data->alf = 1.8;
    user_data->ker = malloc(sizeof(Number)*user_data->row*user_data->col);
    user_data->Wm = malloc(sizeof(Number)*user_data->col*user_data->col);
    user_data->A_cond = malloc(sizeof(Number)*m*n);
    user_data->b_cond = malloc(sizeof(Number)*m);
    user_data->bs = malloc(sizeof(Number)*user_data->row);
    user_data->tt = malloc(sizeof(Number)*user_data->row);

    // set A_cond and b_cond
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            double test = 0;
            if (j == 1)
            {
                if (i == 0) test = 1;
                if (i == 1) test = -1;
            }
            if (j == 3)
            {
                if (i == 0) test = -0.35;
                if (i == 1) test = 0.2;
            }
            user_data->A_cond[j*m + i] = test;
        }
        user_data->b_cond[i] = 0;
    }

    // set Wm
    for (int i = 0; i < user_data->col; i++)
    {
        for (int j = 0; j < user_data->col; j++)
        {
            double test = 0;
            if (i > 0 && i < user_data->col - 1)
            {
                if (j == i - 1 || j == i + 1) test = 1.0;
                if (j == i) test = -2.0;
            }
            user_data->Wm[j*user_data->col + i] = test;
        }
    }

    FILE *bsf = NULL, *ttf = NULL, *kerf = NULL;
//    char fullpath[100] = "..\\x64\\Debug\\";
    char fullpath[100] = "./"; // ".\\";
    strcat(fullpath, path);
//    errno_t err = strcat_s(fullpath, 100, path);
//    errno_t err1 = fopen_s(&bsf, fullpath, "r");  // return 0 if success
    bsf = fopen(fullpath, "r");
//    errno_t err2 = fopen_s(&ttf, "..\\x64\\Debug\\tt.txt", "r");  // return 0 if success
//    errno_t err3 = fopen_s(&kerf, "..\\x64\\Debug\\ker.txt", "r"); // return 0 if success
//    errno_t err2 = fopen_s(&ttf, "tt.txt", "r");
//    errno_t err3 = fopen_s(&kerf, "ker.txt", "r");
    ttf = fopen("tt.txt", "r");
    kerf = fopen("ker.txt", "r");
    for (int i = 0; i < user_data->row; i++)
    {
        double test1, test2;
        fscanf(bsf, "%lf", &test1);
        fscanf(ttf, "%lf", &test2);
        user_data->bs[i] = test1;
        user_data->tt[i] = test2;

        for (int j = 0; j < user_data->col; j++)
        {
            double test3;
            fscanf(kerf, "%lf\t", &test3);
            user_data->ker[j*(user_data->row) + i] = test3;
        }
    }
    fclose(bsf);
    fclose(ttf);
    fclose(kerf);
}

/* Function Implementations */
Bool eval_f(
    Index       n,
    Number*     x,
    Bool        new_x,
    Number*     obj_value,
    UserDataPtr user_data
    )
{
    //assert(n == 34);
    (void)n;

    struct MyUserData* my_data = user_data;
    Index row = my_data->row;
    Index col = my_data->col;
    Number *t = my_data->tt;
    Number *ker = my_data->ker;
    Number *Wm = my_data->Wm;
    Number *bs = my_data->bs;
    Number alf = my_data->alf;


    Index i;
    Number *fkxBs = malloc(sizeof(Number)*row);   // fv*k*xB - bs
    Number *xB = malloc(sizeof(Number)*col);
    Number *WmxB = malloc(sizeof(Number)*col);

    memset(fkxBs, 0, sizeof(Number)*N_ROW);
    memset(WmxB, 0, sizeof(Number)*N_COL);

    memcpy(xB, x, sizeof(Number)*col);

    // calc fkxBs = k*xB
    cblas_dgemv(CblasColMajor, CblasNoTrans, row, col,
        1, ker, row, xB, 1, 0, fkxBs, 1);

    for (i = 0; i < row; i++)
    {
        fkxBs[i] = fkxBs[i] - bs[i];
    }

    cblas_dgemv(CblasColMajor, CblasNoTrans, col, col,
        1, Wm, col, xB, 1, 0, WmxB, 1);



    double tmp1 = cblas_ddot(row, fkxBs, 1, fkxBs, 1);
    double tmp2 = alf*cblas_ddot(col, WmxB, 1, WmxB, 1);


    *obj_value = tmp1 + tmp2;

    free(fkxBs);
    free(xB);
    free(WmxB);

    return TRUE;
}

Bool eval_grad_f_spec(
    Index       n,
    Number* x,
    Bool        new_x,
    Number* grad_f,
    UserDataPtr user_data
)
{
    struct MyUserData* my_data = (struct MyUserData*)user_data;
    Index row = my_data->row;
    Index col = my_data->col;
    Number* t = my_data->tt;
    Number* ker = my_data->ker;
    Number* Wm = my_data->Wm;
    Number* bs = my_data->bs;
    Number alf = my_data->alf;

    Index i, j;

    Number *Wm2 = malloc(sizeof(Number)*col*col);       // Wm^T*Wm
    Number *xB = malloc(sizeof(Number)*col);
    Number *fkxBs = malloc(sizeof(Number)*row);       // (fv*k*xB - bs)

    Number *fk_term = malloc(sizeof(Number)*col);   //  (fv*k)^T*[fv*k*xB - bs]
    Number *Wm_term = malloc(sizeof(Number)*col);   //  Wm^T*Wm*xB


    memcpy(xB, x, sizeof(Number)*col);

    // calc fkxBs = k*xB
    cblas_dgemv(CblasColMajor, CblasNoTrans, row, col,
        1, ker, row, xB, 1, 0, fkxBs, 1);


    for (i = 0; i < row; i++)
    {
        fkxBs[i] = fkxBs[i] - bs[i];
    }

    // calc fk_term
    for (i = 0; i < col; i++)
    {
        fk_term[i] = 0;
        for (j = 0; j < row; j++)  // fk = (fv*k*xB - bs)^T*diag(fv)*k
        {
            fk_term[i] += fkxBs[j] * ker[i*row + j];
        }
    }

    // calc Wm2 = Wm^T*Wm
    cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, col, col, col,
        1, Wm, col, Wm, col, 0, Wm2, col);
    // calc Wm_term = Wm^T*Wm*xB
    cblas_dgemv(CblasColMajor, CblasNoTrans, col, col,
        1, Wm2, col, xB, 1, 0, Wm_term, 1);

    for (i = 0; i < n; i++)
    {

        grad_f[i] = 2*fk_term[i] + 2*alf*Wm_term[i];
    }


    free(Wm2);
    free(xB);
    free(fkxBs);
    free(fk_term);
    free(Wm_term);

    return TRUE;
}


Bool eval_g(
    Index       n,
    Number* x,
    Bool        new_x,
    Index       m,
    Number* g,
    UserDataPtr user_data
)
{
    Number* Ax, * Aeqx, * c, * ceq;
    if (n != m_n) return FALSE;
    if (m != m_m1 + m_m2 + m_m3 + m_m4) return FALSE;

    Ax = (Number*)malloc(sizeof(Number) * m_m1);
    Aeqx = (Number*)malloc(sizeof(Number) * m_m2);
    c = (Number*)malloc(sizeof(Number) * m_m3);
    ceq = (Number*)malloc(sizeof(Number) * m_m4);

    memset(Ax, 0, sizeof(Number) * m_m1);
    memset(Aeqx, 0, sizeof(Number) * m_m2);

    if (new_x && m_m1 != 0)
    {
        cblas_dgemv(CblasColMajor, CblasNoTrans, m_m1, n,
            1, m_A, m_m1, x, 1, 0, Ax, 1);
        memcpy(m_g_Ax, Ax, sizeof(Number) * m_m1);
    }
    // inequality A*x <= b
    memcpy(g, m_g_Ax, sizeof(Number) * m_m1);

    if (new_x && m_m2 != 0)
    {
        cblas_dgemv(CblasColMajor, CblasNoTrans, m_m2, n,
            1, m_Aeq, m_m2, x, 1, 0, Aeqx, 1);
        memcpy(m_g_Aeqx, Aeqx, sizeof(Number) * m_m2);
    }
    // equality Aeq*x = beq
    memcpy(&g[m_m1], Aeqx, sizeof(Number) * m_m2);

    // non linear constraints
    if (m_nonlcon != NULL)
    {
        m_nonlcon(n, x, TRUE, m_m3, m_m4, c, ceq, user_data);
        memcpy(m_jac_g_c, c, sizeof(Number) * m_m3);
        memcpy(m_jac_g_ceq, ceq, sizeof(Number) * m_m4);
    }
    memcpy(&g[m_m1 + m_m2], m_jac_g_c, sizeof(Number) * m_m3);
    memcpy(&g[m_m1 + m_m2 + m_m3], m_jac_g_ceq, sizeof(Number) * m_m4);

    free(Ax);
    free(Aeqx);
    free(c);
    free(ceq);
    return TRUE;
}

Bool eval_jac_g(
    Index       n,
    Number* x,
    Bool        new_x,
    Index       m,
    Index       nele_jac,
    Index* iRow,
    Index* jCol,
    Number* values,
    UserDataPtr user_data
)
{
    if (n != m_n) return FALSE;
    if (m != m_m1 + m_m2 + m_m3 + m_m4) return FALSE;

    if (values == NULL)
    {
        Index row = 0;
        Index col = 0;
        Index idx = 0;
        m_nonnegMatrix = 0;

        // return the structure of the Jacobian
        for (row = 0; row < m_m1; row++)
        {
            for (col = 0; col < n; col++)
            {
                if (fabs(m_A[col * m_m1 + row]) > m_tol)
                {
                    iRow[idx] = row;
                    jCol[idx] = col;
                    idx++;
                }
            }

        }

        for (row = 0; row < m_m2; row++)
        {
            for (col = 0; col < n; col++)
            {
                if (fabs(m_Aeq[col * m_m2 + row]) > m_tol)
                {
                    iRow[idx] = m_m1 + row;
                    jCol[idx] = col;
                    idx++;
                }
            }

        }

        for (row = 0; row < m_m3; row++)
        {
            for (col = 0; col < n; col++)
            {
                iRow[idx] = m_m1 + m_m2 + row;
                jCol[idx] = col;
                idx++;
            }
        }

        for (row = 0; row < m_m4; row++)
        {
            for (col = 0; col < n; col++)
            {
                iRow[idx] = m_m1 + m_m2 + m_m3 + row;
                jCol[idx] = col;
                idx++;
            }
        }
    }
    else
    {
        // return the values of the Jacobian of the constraints
        Index row, col, idx = 0;
        Number* xcopy = (Number*)malloc(sizeof(Number) * m_n);
        Number* result1 = (Number*)malloc(sizeof(Number) * m_m3 * m_n);
        Number* result2 = (Number*)malloc(sizeof(Number) * m_m4 * m_n);
        Number* c = (Number*)malloc(sizeof(Number) * m_m3);
        Number* ceq = (Number*)malloc(sizeof(Number) * m_m4);

        if (m_nonlcon != NULL)
        {
            if (new_x)
            {
                m_nonlcon(m_n, x, TRUE, m_m3, m_m4, c, ceq, user_data);
                memcpy(m_jac_g_c, c, sizeof(Number) * m_m3);
                memcpy(m_jac_g_ceq, ceq, sizeof(Number) * m_m4);

                for (col = 0; col < m_n; col++)
                {
                    memcpy(xcopy, x, sizeof(Number) * n);
                    xcopy[col] = xcopy[col] + m_step;
                    m_nonlcon(n, xcopy, TRUE, m_m3, m_m4, c, ceq, user_data);
                    memcpy(&m_ci[col * m_m3], c, sizeof(Number) * m_m3);
                    memcpy(&m_ceqi[col * m_m4], ceq, sizeof(Number) * m_m4);
                }
            }

            for (col = 0; col < n; col++)
            {
                for (Index i = 0; i < m_m3; i++)
                {
                    result1[col * m_m3 + i] = (m_ci[col * m_m3 + i] - m_jac_g_c[i]) / m_step;
                }
                for (Index i = 0; i < m_m4; i++)
                {
                    result2[col * m_m4 + i] = (m_ceqi[col * m_m4 + i] - m_jac_g_ceq[i]) / m_step;
                }
            }
        }

        if (m_nonnegMatrix == 0)  // trick to calc only once
        {
            for (row = 0; row < m_m1; row++)
            {
                for (col = 0; col < n; col++)
                {
                    if (fabs(m_A[col * m_m1 + row]) > m_tol)
                    {
                        values[idx] = m_A[col * m_m1 + row];
                        idx++;
                    }
                }

            }

            for (row = 0; row < m_m2; row++)
            {
                for (col = 0; col < n; col++)
                {
                    if (fabs(m_Aeq[col * m_m2 + row]) > m_tol)
                    {
                        values[idx] = m_Aeq[col * m_m2 + row];
                        idx++;
                    }
                }

            }

            m_nonnegMatrix = idx;
        }

        idx = m_nonnegMatrix;

        for (row = 0; row < m_m3; row++)
        {
            for (col = 0; col < n; col++)
            {
                values[idx] = result1[col * m_m3 + row];
                idx++;
            }
        }

        for (row = 0; row < m_m4; row++)
        {
            for (col = 0; col < n; col++)
            {
                values[idx] = result2[col * m_m4 + row];
                idx++;
            }
        }

        free(result1);
        free(result2);
        free(c);
        free(ceq);
    }

    return TRUE;
}

Bool eval_h_spec(
    Index       n,
    Number* x,
    Bool        new_x,
    Number      obj_factor,
    Index       m,
    Number* lambda,
    Bool        new_lambda,
    Index       nele_hess,
    Index* iRow,
    Index* jCol,
    Number* values,
    UserDataPtr user_data
)
{
    Index idx = 0; /* nonzero element counter */
    Index row = 0; /* row counter for loop */
    Index col = 0; /* col counter for loop */

    (void)n;
    (void)new_x;
    (void)m;
    (void)new_lambda;
    struct MyUserData* my_data = user_data;

    if (values == NULL)
    {
        /* return the structure. This is a symmetric matrix, fill the lower left
         * triangle only. */

         /* the hessian for this problem is actually dense */
        idx = 0;
        for (row = 0; row < n; row++)
        {
            for (col = 0; col <= row; col++)
            {
                iRow[idx] = row;
                jCol[idx] = col;
                idx++;
            }
        }

        assert(idx == nele_hess);
        (void)nele_hess;
    }
    else
    {
        row = my_data->row;
        col = my_data->col;
        Number* t = my_data->tt;
        Number* ker = my_data->ker;
        Number* Wm = my_data->Wm;
        Number* bs = my_data->bs;
        Number alf = my_data->alf;

        Index i, j;

        Number *fk2 = malloc(sizeof(Number) * col * col);        // (fv*k)^T*(fv*k)
        Number* Wm2 = malloc(sizeof(Number) * col * col);       // Wm^T*Wm


        /* return the values. This is a symmetric matrix, fill the lower left
         * triangle only */

        // calc fk2 = (fv*k)^T*(fv*k)
        cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, col, col, row,
            1, ker, row, ker, row, 0, fk2, col);

        // calc Wm2 = Wm^T*Wm
        cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, col, col, col,
            1, Wm, col, Wm, col, 0, Wm2, col);

        /* fill the objective portion */
        for (i = 0; i < n; i++)
        {
            for (j = 0; j <= i; j++)
            {
                idx = (i + 1) * i / 2 + j;
                values[idx] = 2*obj_factor*(fk2[j*col+i] + alf*Wm2[j*col+i]);
            }
        }

        free(fk2);
        free(Wm2);
    }

    return TRUE;
}

 

gsl_multimin.c

// time consume: 0.103    fun(x): 2959.05

#include "gsl/gsl_multimin.h"
#include "fmincon.h"


double my_f (const gsl_vector *v, void *params)
{
  double *x = (double*)malloc(sizeof(double)*m_n);
  double y;
  struct MyUserData *p = (struct MyUserData*)params;
  for (int i = 0; i < m_n; i++)
  {
    x[i] = gsl_vector_get(v, i);
  }

  eval_f(m_n, x, TRUE, &y, p);

  free(x);
  return y;
}

/* The gradient of f, df = (df/dx, df/dy). */
void my_df (const gsl_vector *v, void *params,
       gsl_vector *df)
{
    double *x = (double*)malloc(sizeof(double)*m_n);
    double *y = (double*)malloc(sizeof(double)*m_n);
    struct MyUserData *p = (struct MyUserData*)params;

    for (int i = 0; i < m_n; i++)
    {
        x[i] = gsl_vector_get(v, i);
    }

    eval_grad_f_spec(m_n, x, TRUE, y, p);

    for (int i = 0; i < m_n; i++)
    {
        gsl_vector_set(df, i, y[i]);
    }

    free(x);
    free(y);
}

/* Compute both f and df together. */
void my_fdf (const gsl_vector *x, void *params,
        double *f, gsl_vector *df)
{
  *f = my_f(x, params);
  my_df(x, params, df);
}

int gsl_multimin ()
{
  size_t iter = 0;
  int status;
  m_n = 30;
  m_m1 = 2;

  const gsl_multimin_fdfminimizer_type *T;
  gsl_multimin_fdfminimizer *s;

  Init_UserData(m_n, m_m1, &my_data, "bs1.txt");

  gsl_vector *x;
  gsl_multimin_function_fdf my_func;

  my_func.n = m_n;
  my_func.f = my_f;
  my_func.df = my_df;
  my_func.fdf = my_fdf;
  my_func.params = &my_data;

  x = gsl_vector_alloc (m_n);
  for (int i = 0; i < m_n; i++)
  {
      gsl_vector_set(x, i, 0.99);
  }

//  T = gsl_multimin_fdfminimizer_conjugate_pr;
  T = gsl_multimin_fdfminimizer_vector_bfgs2;
  s = gsl_multimin_fdfminimizer_alloc (T, m_n);

  gsl_multimin_fdfminimizer_set (s, &my_func, x, 0.01, 1e-4);

  do
    {
      iter++;
      status = gsl_multimin_fdfminimizer_iterate (s);

      if (status)
        break;

      status = gsl_multimin_test_gradient (s->gradient, 1e-3);

      if (status == GSL_SUCCESS)
        printf ("Minimum found at:\n");

      printf("%5d ", iter);
      for (int i = 0; i < m_n; i++)
      {
          printf("%.5f ", gsl_vector_get(s->x, i));
      }
      printf("%10.5f\n", s->f);
    }
  while (status == GSL_CONTINUE && iter < 100);

  gsl_multimin_fdfminimizer_free (s);
  gsl_vector_free (x);

  return 0;
}

 

Ipopt.c

// time consume: 0.052     fun(x): 2980.62

#include "fmincon.h"

void InfoPrint(FILE* file, Index n, Index m, Number* x, Number* lambda,
    Number* mult_x_L, Number* mult_x_U, Number fval)
{
    Index i;

    fprintf(file, "\n\nSolution of the primal variables, x\n");
    for (i = 0; i < m_n; i++)
    {
        fprintf(file, "x[%d] = %e\n", i, x[i]);
    }

    fprintf(file, "\n\nSolution of the constraint multipliers, lambda\n");
    for (i = 0; i < m; i++)
    {
        fprintf(file, "lambda[%d] = %e\n", i, lambda[i]);
    }
    fprintf(file, "\n\nSolution of the bound multipliers, z_L and z_U\n");
    for (i = 0; i < m_n; i++)
    {
        fprintf(file, "z_L[%d] = %e\n", i, mult_x_L[i]);
    }
    for (i = 0; i < m_n; i++)
    {
        fprintf(file, "z_U[%d] = %e\n", i, mult_x_U[i]);
    }

    fprintf(file, "\n\nObjective value\nf(x*) = %e\n", fval);
}

enum ApplicationReturnStatus fmincon(
    Eval_F_CB obj_func,        // (in) pointer, the objective function of above form
    Index n_var,               // (in) integer, the number of components in x
    Number* x,                 // (in, out) vector, As Input: Starting point; As Output: Optimal solution
    Index m_lc,                // (in) integer, the number of components in linear inequalities, 0 if not exist
    Number* A,                 // (in) matrix, linear inequalities A*x ≤ b, NULL if not exist
    Number* b,                 // (in) vector, linear inequalities A*x ≤ b, NULL if not exist
    Index m_leqc,              // (in) integer, the number of components in linear equalities, 0 if not exist
    Number* Aeq,               // (in) matrix, linear equalities Aeq*x = beq, NULL if not exist
    Number* beq,               // (in) vector, linear equalities Aeq*x = beq, NULL if not exist
    Number* lb,                // (in) vector, lower bounds of x, lb <= x <= ub, NULL if not exist
    Number* ub,                // (in) vector, upper bounds of x, lb <= x <= ub, NULL if not exist
    Index m_nl,                // (in) integer, the number of non linear inequalities, 0 if not exist
    Index m_nleq,              // (in) integer, the number of non linear equalities, 0 if not exist
    Eval_NLC_CB nonlcon,       // (in) pointer, the non linear constraints function of above form, NULL if not exist
    Index m_opt,               // (in) integer, number of options, 0 if take default
    char*** options,            // (in) string pair to describe the options, the form is char[:][2][:], NULL if take default
    UserDataPtr user_data,     // (in) pointer, the parameters in objective functions, NULL if not exist
    Number* fval,               // (out) real, the optimized value of objective function
    FILE* output,               // (out) file pointer, write some info about calculation to the file
    Number* lambda,            // (out) vector, Lagrange multipliers at the solution, length = m_lc+mleqc+m_nl+m_nleq
    Number* grad,              // (out) vector, Gradient at the solution, length = n_var
    Number* hessian            // (out) matrix, Approximate Hessian, length = n_var*n_var
)
{
    Index m;                             /* number of constraints */
    Index nele_jac;                      /* number of nonzeros in the Jacobian of the constraints */
    Index nele_hess;                     /* number of nonzeros in the Hessian of the Lagrangian (lower or upper triangular part only) */
    Index index_style;                   /* indexing style for matrices */
    Number* g_L = NULL;                  /* lower bounds on g */
    Number* g_U = NULL;                  /* upper bounds on g */
    IpoptProblem nlp = NULL;             /* IpoptProblem */
    enum ApplicationReturnStatus status; /* Solve return code */
    Number* mult_x_L = NULL;             /* lower bound multipliers at the solution */
    Number* mult_x_U = NULL;             /* upper bound multipliers at the solution */
    Index i;                             /* generic counter */

    m_tol = 1e-10;         // set default tolerance
    m_debuglog = output;

    m_g_Ax = (Number*)malloc(sizeof(Number) * m_lc);
    m_g_Aeqx = (Number*)malloc(sizeof(Number) * m_leqc);
    m_jac_g_c = (Number*)malloc(sizeof(Number) * m_nl);     // cache c
    m_jac_g_ceq = (Number*)malloc(sizeof(Number) * m_nleq);    // cache ceq

    m_ci = (Number*)malloc(sizeof(Number) * m_nl * n_var);              // cache c(xi+h)
    m_ceqi = (Number*)malloc(sizeof(Number) * m_nleq * n_var);            // cache ceq(xi+h)
    m_cij = (Number*)malloc(sizeof(Number) * m_nl * n_var * n_var);             // cache c(xi+h, xj+h)
    m_ceqij = (Number*)malloc(sizeof(Number) * m_nleq * n_var * n_var);           // cache ceq(xi+h, xj+h)

    m_func = obj_func;
    m_nonlcon = nonlcon;
    m_A = A;
    m_b = b;
    m_Aeq = Aeq;
    m_beq = beq;

    /* set the number of variables and the values for the variable bounds */
    /* and check the initial value, if it is not feasible, reset it. */
    m_n = n_var;
    m_lb = lb;
    m_ub = ub;
    for (i = 0; i < n_var; i++)
    {
        if (x[i] <= m_lb[i] || x[i] >= m_ub[i])
        {
            if (m_ub[i] - m_lb[i] > 1)
            {
                x[i] = m_lb[i] + 1;
            }
            else
            {
                x[i] = (m_lb[i] + m_ub[i]) / 2;
            }
        }
    }

    /* set the number of constraints and allocate space for the bounds */
    m_m1 = m_lc;
    m_m2 = m_leqc;
    m_m3 = m_nl;
    m_m4 = m_nleq;
    m = m_m1 + m_m2 + m_m3 + m_m4;
    g_L = (Number*)malloc(sizeof(Number) * m);
    g_U = (Number*)malloc(sizeof(Number) * m);
    /* set the values of the constraint bounds */
    for (i = 0; i < m; i++)
    {
        if (i < m_m1)  // inequality
        {
            g_L[i] = -2e19;
            g_U[i] = b[i];
        }
        else if (i < m_m1 + m_m2)  // equality
        {
            g_L[i] = g_U[i] = beq[i];
        }
        else if (i < m_m1 + m_m2 + m_m3)
        {
            g_L[i] = -2e19;
            g_U[i] = 0;
        }
        else
        {
            g_L[i] = g_U[i] = 0;
        }
    }

    /* set the number of nonzeros in the Jacobian and Hessian */
    i = 0;
    for (Index j = 0; j < m_n; j++)
    {
        for (Index k = 0; k < m_m1; k++)
        {
            if (fabs(A[j * m_m1 + k]) > m_tol)
            {
                i++;
            }
        }
        for (Index k = 0; k < m_m2; k++)
        {
            if (fabs(Aeq[j * m_m2 + k]) > m_tol)
            {
                i++;
            }
        }
    }
    nele_jac = i + (m_m3 + m_m4) * m_n;
    nele_hess = m_n * (m_n + 1) / 2;

    /* set the indexing style to C-style (start counting of rows and column indices at 0) */
    index_style = 0;

    /* create the IpoptProblem */
    nlp = CreateIpoptProblem(m_n, m_lb, m_ub, m, g_L, g_U, nele_jac, nele_hess, index_style,
        m_func, &eval_g, &eval_grad_f_spec, &eval_jac_g, &eval_h_spec);

    /* We can free the memory now - the values for the bounds have been
    * copied internally in CreateIpoptProblem
    */
    free(g_L);
    free(g_U);

    /* Set some options.  Note the following ones are only examples,
    * they might not be suitable for your problem.
    */
    AddIpoptNumOption(nlp, "tol", 1e-7);
    AddIpoptStrOption(nlp, "mu_strategy", "adaptive");
    AddIpoptStrOption(nlp, "output_file", "ipopt.out");
    AddIpoptIntOption(nlp, "print_level", 5);

    m_tol = 1e-7;
    m_step = sqrt(m_tol);

    /* allocate space to store the bound multipliers at the solution */
    mult_x_L = (Number*)malloc(sizeof(Number) * m_n);
    mult_x_U = (Number*)malloc(sizeof(Number) * m_n);

    /* Set the callback method for intermediate user-control.
    * This is not required, just gives you some intermediate control in
    * case you need it.
    */
    /* SetIntermediateCallback(nlp, intermediate_cb); */

    /* solve the problem */
    status = IpoptSolve(nlp, x, grad, fval, lambda, mult_x_L, mult_x_U, user_data);

    if (status == Solve_Succeeded)
    {
        InfoPrint(output, m_n, m, x, lambda, mult_x_L, mult_x_U, *fval);
    }
    else
    {
        fprintf(output, "\n\nERROR OCCURRED DURING IPOPT OPTIMIZATION.\n");
    }

    /* free allocated memory */
    FreeIpoptProblem(nlp);
    free(mult_x_L);
    free(mult_x_U);

    free(m_ci);
    free(m_ceqi);
    free(m_cij);
    free(m_ceqij);
    free(m_g_Ax);
    free(m_g_Aeqx);
    free(m_jac_g_c);
    free(m_jac_g_ceq);

    return status;
}

int Ipopt()
{
    enum ApplicationReturnStatus status;
    Index n = 30;      // variable number
    Index m1 = 2;      // inequality constraint number
    Index m2 = 0;      // equality constraint number
    Index m3 = 0;      // inequality non linear constraint number
    Index m4 = 0;      // equality non linear constraint number
    Number *x0 = (Number*)malloc(sizeof(Number)*n);
    struct MyUserData my_data;

    Number *Aeq = NULL;
    Number *beq = NULL;

    // lower bound
    Number lb[30] = { //1e-4, 0.0, 1e-4, 495,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    };
    // upper bound
    Number ub[30] = { //0.05, 1000.0, 0.05, 505,
        100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
        100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
        100, 100, 100, 100, 100, 100, 100, 100, 100, 100
    };

    Eval_NLC_CB nonLinCons = NULL;   // non linear constraints
    Index n_opt = 4;     // how many options need to set
    char ***opts = (char***)malloc(sizeof(char**)*n_opt);
    for (Index i = 0; i < n_opt; i++)
    {
        opts[i] = (char**)malloc(sizeof(char*)* 2);
    }
    opts[0][0] = "tol"; opts[0][1] = "1e-7";   // set tolerance = 1e-7
    opts[1][0] = "mu_strategy"; opts[1][1] = "adaptive";  // set mu strategy as adaptive
    opts[2][0] = "output_file"; opts[2][1] = "ipopt.out";   // set the output file as ipopt.out
    opts[3][0] = "print_level"; opts[3][1] = "5";  // 3 will be better

    Number result;  // store the final function result
    Number *lambda = (Number*)malloc(sizeof(Number)*m1);  // store the the lagrangian multiplier
    Number *grad = (Number*)malloc(sizeof(Number)*n);     // store the final gradient
    Number *hess = (Number*)malloc(sizeof(Number)*n*n);   // store the final hess, which is not implemented yet

    for (Index idx = 0; idx < 10; idx++)
    {
        char num[3] = { 0 };    // need one more char to store end symbol \0
//        _itoa_s(idx + 1, num, 3, 10);     // 轉成10進制字符串
//        itoa(idx + 1, num, 10);
        snprintf(num, 3, "%d", idx+1);
        char bsfile[50] = "bs";
        char* ext = ".txt";
//        strcat_s(bsfile, 50, num);     // bsxxx
//        strcat_s(bsfile, 50, ext);     // bsxxx.txt
        strcat(bsfile, num);
        strcat(bsfile, ext);
        Init_UserData(n, m1, &my_data, bsfile);

        memset(x0, 0, sizeof(double)*n);  // this is necessary to ensure x0 are number rather than NaN

        status = fmincon(
            eval_f,
            n,
            x0,
            m1,
            my_data.A_cond,
            my_data.b_cond,
            m2,
            Aeq,
            beq,
            lb,
            ub,
            m3,
            m4,
            nonLinCons,
            n_opt,
            opts,
            &my_data,
            &result,
            m_debuglog,
            lambda,
            grad,
            hess
        );

//        char xfilename[50] = "..\\x64\\Debug\\x";
        char xfilename[50] = "./x";
        strcat(xfilename, num);
        strcat(xfilename, ext);
//        strcat_s(xfilename, 50, num);
//        strcat_s(xfilename, 50, ext);
        FILE *xfile = NULL, *testlog = NULL;
        xfile = fopen(xfilename, "r");
        testlog = fopen("testlog.txt", "a+");
//        fopen_s(&xfile, xfilename, "r");
//        fopen_s(&testlog, "..\\x64\\Debug\\testlog.txt", "a+");
//		fopen_s(&testlog, "testlog.txt", "a+");
        fprintf(testlog, "for the %d th group parameters: \n", idx);
        for (int i = 0; i < n; i++)
        {
            double test;
            fscanf(xfile, "%lf", &test);
            fprintf(testlog, "%g\n", x0[i]);
        }
        fprintf(testlog, "the function value is: %g\n\n\n\n", result);
        fclose(xfile);
        fclose(testlog);

        fclose(m_debuglog);   // to avoid open logfile many times
    }


    free(x0);

    system("pause");
    return 0;
}

 

osqp.c

// time consume: 0.074    fun(x): 2980.76

#include "osqp.h"
#include "fmincon.h"


int osqp() {
  m_n = 30;
  m_m1 = 2;

  // Load problem data
  c_float P_x[15*31];
  c_int   P_nnz  = m_n*(m_n+1)/2;
  c_int   P_i[15*31];
  c_int   P_p[31] = {
      0,  1,  2,  3,  4,  5,
      6,  7,  8,  9,  10, 11,
      12, 13, 14, 15, 16, 17,
      18, 19, 20, 21, 22, 23,
      24, 25, 26, 27, 28, 29, 15*31
  };

  c_float q[30];
  double *ker2 = (double*)malloc(sizeof(double)*m_n*m_n);
  double *Wm2 = (double*)malloc(sizeof(double)*m_n*m_n);
  double constant_term = 0;

  c_float A_x[30] = {
      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
      1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
      1.0, 1.0, 1.0, 1.0, 1.0, 1.0
  };
  c_int   A_nnz  = m_n;
  c_int   A_i[30] = {
      0,  1,  2,  3,  4,  5,
      6,  7,  8,  9,  10, 11,
      12, 13, 14, 15, 16, 17,
      18, 19, 20, 21, 22, 23,
      24, 25, 26, 27, 28, 29
  };
  c_int   A_p[31] = {
      0,  1,  2,  3,  4,  5,
      6,  7,  8,  9,  10, 11,
      12, 13, 14, 15, 16, 17,
      18, 19, 20, 21, 22, 23,
      24, 25, 26, 27, 28, 29, 30
  };

  c_float l[30] = {
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
      0.0, 0.0, 0.0, 0.0, 0.0, 0.0
  };
  c_float u[30] = {
      100, 100, 100, 100, 100, 100,
      100, 100, 100, 100, 100, 100,
      100, 100, 100, 100, 100, 100,
      100, 100, 100, 100, 100, 100,
      100, 100, 100, 100, 100, 100
  };

  // Exitflag
  c_int exitflag = 0;

  // Workspace structures
  OSQPWorkspace *work;
  OSQPSettings  *settings = (OSQPSettings *)c_malloc(sizeof(OSQPSettings));
  OSQPData      *data     = (OSQPData *)c_malloc(sizeof(OSQPData));

  memset(q, 0, sizeof(double)*m_n);
  Init_UserData(m_n, m_m1, &my_data, "bs1.txt");

  // calc q
  cblas_dgemv(CblasColMajor, CblasTrans, my_data.row, my_data.col,
              -2, my_data.ker, my_data.row, my_data.bs, 1, 0, q, 1);

  // calc P
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, my_data.col, my_data.col, my_data.row,
              1, my_data.ker, my_data.row, my_data.ker, my_data.row, 0, ker2, my_data.col);
  cblas_dgemm(CblasColMajor, CblasTrans, CblasNoTrans, my_data.col, my_data.col, my_data.col,
      1, my_data.Wm, my_data.col, my_data.Wm, my_data.col, 0, Wm2, my_data.col);

  for (int i = 0; i < m_n; i++)
  {
      P_p[i] = i*(i+1)/2;
      for (int j = 0; j <= i; j++)
      {
          int idx = P_p[i] + j;
          P_i[idx] = j;
          P_x[idx] = 2*ker2[i*my_data.col + j] + 2*my_data.alf*Wm2[i*my_data.col + j];
      }
  }

  // calc constant term
  constant_term = cblas_ddot(my_data.row, my_data.bs, 1, my_data.bs, 1);

  // Populate data
  if (data) {
    data->n = m_n;
    data->m = 30;
    data->P = csc_matrix(data->n, data->n, P_nnz, P_x, P_i, P_p);
    data->q = q;
    data->A = csc_matrix(30, data->n, A_nnz, A_x, A_i, A_p);
    data->l = l;
    data->u = u;
  }

  // Define solver settings as default
  if (settings) osqp_set_default_settings(settings);

  // Setup workspace
  exitflag = osqp_setup(&work, data, settings);

  // Solve Problem
  osqp_solve(work);

  // Clean workspace
  osqp_cleanup(work);
  if (data) {
    if (data->A) c_free(data->A);
    if (data->P) c_free(data->P);
    c_free(data);
  }
  if (settings)  c_free(settings);
  free(ker2);
  free(Wm2);

  printf("const term: %g\n", constant_term);
  return exitflag;
}

 

由於這部分代碼比較亂,是從各個庫的樣例代碼中修改而來。且目標函數涉及參數較多,是從文件中讀入參數,有部分代碼來自個人vs工程,故僅作爲個人備份和寫代碼參考,就不給出完整可運行工程包了。單個方法測試結果已寫在代碼註釋之中,可供參考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章