Log in
/*-----------------------------------------------------------------------
 *
 * Minimise    f
 *
 * subject to      -0.5 <= x1 <=  INFTY
 *                   -2 <= x2 <=  INFTY
 *                    0 <= x3 <=  2
 *                   -2 <= x4 <=  2
 *                         g1 ==  1
 *               -INFTY <= g2 <= -1
 *                  2.5 <= g3 <=  5
 *
 * where         f (x1,x2,x3,x4) = x1^2 + 2 x2^2 - x3
 *               g1(x1,x2,x3,x4) = x1^2 + x3^2 + x1x3
 *               g2(x1,x2,x3,x4) = x3 - x4
 *               g3(x1,x2,x3,x4) = x2 + x4
 *
 * Optimal solution
 *                     x*  = (0, 0.5, 1, 2)
 *                   f(x*) = -0.5
 *                   g(x*) = (1, -1, 2.5)
 *
 *-----------------------------------------------------------------------*/
 
#include <iostream>
 
#include "worhp/worhp.h"
 
// Declare user functions, implementation later
 
// Objective function
void UserF(OptVar *opt, Workspace *wsp, Params *par, Control *cnt);
// Function of constraints
void UserG(OptVar *opt, Workspace *wsp, Params *par, Control *cnt);
// Gradient of objective function
void UserDF(OptVar *opt, Workspace *wsp, Params *par, Control *cnt);
// Jacobian of constraints
void UserDG(OptVar *opt, Workspace *wsp, Params *par, Control *cnt);
// Hessian of Lagrangian
void UserHM(OptVar *opt, Workspace *wsp, Params *par, Control *cnt);
 
 
int main()
{
    /*
	 * WORHP data structures
     *
     * OptVar contains the variables, constraint values and multipliers.
     * Workspace encapsulates all workspace and working variables for WORHP.
     * Params contains all WORHP parameters.
     * Control contains things for reverse communication flow control.
     */
    OptVar    opt;
    Workspace wsp;
    Params    par;
    Control   cnt;
 
    // Check Version of library and header files
    CHECK_WORHP_VERSION
 
    // Properly zeros everything, or else the following routines could get confused
    WorhpPreInit(&opt, &wsp, &par, &cnt);
 
    // Uncomment this to get more info on data structures
    //WorhpDiag(&opt, &wsp, &par, &cnt);
 
    /*
     * Parameter initialisation routine that must be called
     * when using ReadParamsNoInit instead of ReadParams.
     */
    int status;
    InitParams(&status, &par);
 
    /*
     * We can now set parameters that may be overruled by those in the
     * parameter file. This is useful for setting a non-default standard
     * parameter value that may still be overwritten.
     */
    par.NLPprint = 1;  // Let's prefer the slim output format
                       // unless the parameter file says differently
 
    /*
     * Parameter XML import routine that does not reset
     * all parameters to default values (InitParams does this)
     */
    ReadParamsNoInit(&status, "worhp.xml", &par);
    if (status == DataError || status == InitError)
    {
        return EXIT_FAILURE;
    }
 
    /*
     * WORHP data structure initialisation routine.
     * Calling this routine prior to WORHP is mandatory.
     * Before calling WorhpInit, set the problem and matrix dimensions as
     *
     * opt.n      = number of variables,
     * opt.m      = number of constraints (lin + nonlin, excluding box con's),
     * wsp.DF.nnz = nonzero entries of the objective function gradient,
     * wsp.DG.nnz = nonzero entries of the constraint Jacobian,
     * wsp.HM.nnz = nonzero entries of the Lagrange Hessian.
     *
     * Set nnz to 'WorhpMatrix_Init_Dense' to have WorhpInit allocate and
     * create a dense matrix structure appropriate for the matrix kind and
     * its dimensions. Setting it to its dense dimension achieves the same.
     */
    opt.n = 4;  // This problem has 4 variables
    opt.m = 3;  // and 3 constraints (excluding box constraints)
 
    // All derivatives for this problem have a sparse structure, so
    // set the amount of nonzeros here
    wsp.DF.nnz = 3;
    wsp.DG.nnz = 6;
    wsp.HM.nnz = 1 + opt.n;  // 1 entry on strict lower triangle
                             // plus full diagonal
 
    WorhpInit(&opt, &wsp, &par, &cnt);
    if (cnt.status != FirstCall)
    {
        std::cout << "Main: Initialisation failed." << std::endl;
        return EXIT_FAILURE;
    }
 
    /*
     * These pointers give access to the essential user data:
     *
     * opt.X[0] to opt.X[opt.n - 1]           : Optimisation variables
     * opt.Lambda[0] to opt.Lambda[opt.n - 1] : Multipliers for the constraints
     *                                          on X ("box constraints")
     * opt.G[0] to opt.G[opt.m - 1]           : Linear and nonlinear constraints
     * opt.Mu[0] to opt.Mu[opt.m - 1]         : Multipliers for the constraints on G
     *
     * Set initial values of X, Lambda and Mu here.
     * G need not be initialised.
     */
    opt.X[0] = 2.0;
    opt.X[1] = 2.0;
    opt.X[2] = 1.0;
    opt.X[3] = 0.0;
    opt.Lambda[0] = 0.0;
    opt.Lambda[1] = 0.0;
    opt.Lambda[2] = 0.0;
    opt.Lambda[3] = 0.0;
    opt.Mu[0] = 0.0;
    opt.Mu[1] = 0.0;
    opt.Mu[2] = 0.0;
 
    /*
     * Set lower and upper bounds on the variables and constraints.
     * Use +/-par.Infty to signal "unbounded".
     *
     * XL and XU are lower and upper bounds ("box constraints") on X.
     * GL and GU are lower and upper bounds on G.
     */
    opt.XL[0] = -0.5;
    opt.XU[0] =  par.Infty;
    opt.XL[1] = -2.0;
    opt.XU[1] =  par.Infty;
    opt.XL[2] =  0.0;
    opt.XU[2] =  2.0;
    opt.XL[3] = -2.0;
    opt.XU[3] =  2.0;
 
    opt.GL[0] =  1.0;  // set opt.GL[i] == opt.GU[i]
    opt.GU[0] =  1.0;  // for equality constraints
    opt.GL[1] = -par.Infty;
    opt.GU[1] = -1.0;
    opt.GL[2] =  2.5;
    opt.GU[2] =  5.0;
 
    /*
     * Specify matrix structures in CS format, using Fortran indexing,
     * i.e. 1...N instead of 0...N-1, to describe the matrix structure.
     */
 
    // Define DF as row vector, column index is ommited
    if (wsp.DF.NeedStructure)
    {
        // only set the nonzero entries, so omit the 4th entry,
        // which is a structural zero
        wsp.DF.row[0] = 1;
        wsp.DF.row[1] = 2;
        wsp.DF.row[2] = 3;
    }
 
    // Define DG as CS-matrix
    if (wsp.DG.NeedStructure)
    {
        // only set the nonzero entries in column-major order
        wsp.DG.row[0] = 1;
        wsp.DG.col[0] = 1;
 
        wsp.DG.row[1] = 3;
        wsp.DG.col[1] = 2;
 
        wsp.DG.row[2] = 1;
        wsp.DG.col[2] = 3;
 
        wsp.DG.row[3] = 2;
        wsp.DG.col[3] = 3;
 
        wsp.DG.row[4] = 2;
        wsp.DG.col[4] = 4;
 
        wsp.DG.row[5] = 3;
        wsp.DG.col[5] = 4;
    }
 
    // Define HM as a diagonal LT-CS-matrix, but only if needed by WORHP
    if (wsp.HM.NeedStructure)
    {
        /*
         * only set the nonzero entries, with the strictly lower triangle first,
         * followed by ALL diagonal entries, so even the entry at (4, 4)
         * even though it is a structural zero
         */
 
        // strict lower triangle
        wsp.HM.row[0] = 3;
        wsp.HM.col[0] = 1;
 
        // diagonal
        for (int i = 0; i < opt.n; i += 1)
        {
            wsp.HM.row[wsp.HM.nnz - opt.n + i] = i + 1;
            wsp.HM.col[wsp.HM.nnz - opt.n + i] = i + 1;
        }
    }
 
    /*
     * WORHP Reverse Communication loop.
     * In every iteration poll GetUserAction for the requested action, i.e. one
     * of {callWorhp, iterOutput, evalF, evalG, evalDF, evalDG, evalHM, fidif}.
     *
     * Make sure to reset the requested user action afterwards by calling
     * DoneUserAction, except for 'callWorhp' and 'fidif'.
     */
    while (cnt.status < TerminateSuccess && cnt.status > TerminateError)
    {
        /*
         * WORHP's main routine.
         * Do not manually reset callWorhp, this is only done by the FD routines.
         */
        if (GetUserAction(&cnt, callWorhp))
        {
            Worhp(&opt, &wsp, &par, &cnt);
            // No DoneUserAction!
        }
 
        /*
         * Show iteration output.
         * The call to IterationOutput() may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, iterOutput))
        {
            IterationOutput(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, iterOutput);
        }
 
        /*
         * Evaluate the objective function.
         * The call to UserF may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, evalF))
        {
            UserF(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, evalF);
        }
 
        /*
         * Evaluate the constraints.
         * The call to UserG may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, evalG))
        {
            UserG(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, evalG);
        }
 
        /*
         * Evaluate the gradient of the objective function.
         * The call to UserDF may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, evalDF))
        {
            UserDF(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, evalDF);
        }
 
        /*
         * Evaluate the Jacobian of the constraints.
         * The call to UserDG may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, evalDG))
        {
            UserDG(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, evalDG);
        }
 
        /*
         * Evaluate the Hessian matrix of the Lagrange function (L = f + mu*g)
         * The call to UserHM may be replaced by user-defined code.
         */
        if (GetUserAction(&cnt, evalHM))
        {
            UserHM(&opt, &wsp, &par, &cnt);
            DoneUserAction(&cnt, evalHM);
        }
 
        /*
         * Use finite differences with RC to determine derivatives
         * Do not reset fidif, this is done by the FD routine.
         */
        if (GetUserAction(&cnt, fidif))
        {
            WorhpFidif(&opt, &wsp, &par, &cnt);
            // No DoneUserAction!
        }
    }
 
    // Translate the WORHP status flag into a meaningful message.
    StatusMsg(&opt, &wsp, &par, &cnt);
    // Deallocate all data structures.
    // Data structures must not be accessed after this call.
    WorhpFree(&opt, &wsp, &par, &cnt);
 
    return EXIT_SUCCESS;
}
 
 
void UserF(OptVar *opt, Workspace *wsp, Params *par, Control *cnt)
{
    double *X = opt->X;  // Abbreviate notation
 
    opt->F = wsp->ScaleObj * (X[0] * X[0] + 2.0 * X[1] * X[1] - X[2]);
}
 
void UserG(OptVar *opt, Workspace *wsp, Params *par, Control *cnt)
{
    double *X = opt->X;  // Abbreviate notation
 
    opt->G[0] = X[0] * X[0] + X[2] * X[2] + X[0] * X[2];
    opt->G[1] = X[2] - X[3];
    opt->G[2] = X[1] + X[3];
}
 
void UserDF(OptVar *opt, Workspace *wsp, Params *par, Control *cnt)
{
    wsp->DF.val[0] = wsp->ScaleObj * 2.0 * opt->X[0];
    wsp->DF.val[1] = wsp->ScaleObj * 4.0 * opt->X[1];
    wsp->DF.val[2] = wsp->ScaleObj * -1.0;
}
 
void UserDG(OptVar *opt, Workspace *wsp, Params *par, Control *cnt)
{
    wsp->DG.val[0] = 2.0 * opt->X[0] + opt->X[2];
    wsp->DG.val[1] = 1.0;
    wsp->DG.val[2] = opt->X[0] + 2.0 * opt->X[2];
    wsp->DG.val[3] = 1.0;
    wsp->DG.val[4] = -1.0;
    wsp->DG.val[5] = 1.0;
}
 
void UserHM(OptVar *opt, Workspace *wsp, Params *par, Control *cnt)
{
    // Only scale the F part of HM
    wsp->HM.val[0] = opt->Mu[0];
    wsp->HM.val[1] = wsp->ScaleObj * 2.0 + 2.0 * opt->Mu[0];
    wsp->HM.val[2] = wsp->ScaleObj * 4.0;
    wsp->HM.val[3] = 2.0 * opt->Mu[0];
    wsp->HM.val[4] = 0.0;
}