/* nag_opt_lp (e04mfc) Example Program.
 *
 * Copyright 2014 Numerical Algorithms Group.
 *
 * Mark 2, 1991.
 * Mark 6 revised, 2000.
 * Mark 8 revised, 2004.
 */

/* This sample linear program (LP) is a portfolio investment problem
 * (see Chapter 7, pp 258--262 of ``Numerical Linear Algebra and
 * Optimization'', by Gill, Murray and Wright, Addison Wesley, 1991).
 * The problem involves the rearrangement of a portfolio of three
 * stocks, Glitter, Risky and Trusty, so that the net worth of the
 * investor is maximized.
 * The problem is characterized by the following data:
 *                           Glitter     Risky        Trusty
 * 1990 Holdings                75       1000           25
 * 1990 Priceshare($)           20          2          100
 * 2099 Priceshare($)           18          3          102
 * 2099 Dividend                 5          0            2
 *
 * The variables x[0], x[1] and x[2] represent the change in each of
 * the three stocks.
 */

#include <nag.h>
#include <stdio.h>
#include <nag_stdlib.h>
#include <nag_string.h>
#include <nage04.h>

#define A(I, J) a[(I) *tda + J]

int main(void)
{
  const char  *optionsfile = "e04mfce.opt";
  Integer     exit_status = 0;
  Nag_Boolean print;
  Integer     n, nbnd, nclin, tda;
  Nag_E04_Opt options;
  double      *a = 0, bigbnd, *bl = 0, *bu = 0, *cvec = 0, objf, *x = 0;
  Nag_Comm    comm;
  NagError    fail;

  INIT_FAIL(fail);


  printf("nag_opt_lp (e04mfc) Example Program Results\n");
  /* Set the actual problem dimensions.
   * n      = the number of variables.
   * nclin  = the number of general linear constraints (may be 0).
   */
  n = 3;
  nclin = 5;
  nbnd = n+nclin;
  if (n >= 1 && nclin >= 0)
    {
      if (!(x = NAG_ALLOC(n, double)) ||
          !(cvec = NAG_ALLOC(n, double)) ||
          !(a = NAG_ALLOC(nclin*n, double)) ||
          !(bl = NAG_ALLOC(nbnd, double)) ||
          !(bu = NAG_ALLOC(nbnd, double)))
        {
          printf("Allocation failure\n");
          exit_status = -1;
          goto END;
        }
      tda = n;
    }
  else
    {
      printf("Invalid n or nclin.\n");
      exit_status = 1;
      return exit_status;
    }

  /* Define the value used to denote ``infinite'' bounds. */
  bigbnd = 1e+25;

  /* Objective function:  maximize  5*X[0] + 2*X[2], or equivalently,
   * minimize -5*X[0] - 2*X[2].
   */
  cvec[0] = -5.0;
  cvec[1] = 0.0;
  cvec[2] = -2.0;

  /* a  = the general constraint matrix.
   * bl = the lower bounds on  x  and  A*x.
   * bu = the upper bounds on  x  and  A*x.
   * x  = the initial estimate of the solution.
   *
   * A nonnegative amount of stock must be present after rearrangement.
   * For Glitter:  x[0] + 75 >= 0.
   */
  bl[0] = -75.0;
  bu[0] = bigbnd;

  /* For Risky:    x[1] + 1000 >= 0.0 */
  bl[1] = -1000.0;
  bu[1] = bigbnd;

  /* For Trusty:   x[2] + 25 >= 0.0 */
  bl[2] = -25.0;
  bu[2] = bigbnd;

  /* The current value of the portfolio must be the same after
   * rearrangement, i.e.,
   *  20*(75+x[0]) + 2*(1000+x[1]) + 100*(25+x[2]) = 6000, or
   *  20*x[0] + 2*x[1] + 100*x[2] = 0.
   */
  A(0, 0) = 20.0;
  A(0, 1) = 2.0;
  A(0, 2) = 100.0;
  bl[n] = 0.0;
  bu[n] = 0.0;

  /* The value of the portfolio must increase by at least 5 per cent
   * at the end of the year, i.e.,
   * 18*(75+x[0]) + 3*(1000+x[1]) + 102*(25+x[2]) >= 6300, or
   * 18*x[0] + 3*x[1] + 102*x[2] >= -600.
   */
  A(1, 0) = 18.0;
  A(1, 1) = 3.0;
  A(1, 2) = 102.0;
  bl[n + 1] = -600.0;
  bu[n + 1] = bigbnd;

  /* There are three ``balanced portfolio'' constraints.  The value of
   * a stock must constitute at least a quarter of the total final
   * value of the portfolio.  After rearrangement, the value of the
   * portfolio after is  20*(75+x[0]) + 2*(1000+x[1]) + 100*(25+x[2]).
   *
   * If Glitter is to constitute at least a quarter of the final
   * portfolio, then  15*x[0] - 0.5*x[1] - 25*x[2] >= 0.
   */
  A(2, 0) = 15.0;
  A(2, 1) = -0.5;
  A(2, 2) = -25.0;
  bl[n + 2] = 0.0;
  bu[n + 2] = bigbnd;

  /* If Risky is to constitute at least a quarter of the final
   * portfolio, then  -5*x[0] + 1.5*x[1] - 25*x[2] >= -500.
   */
  A(3, 0) = -5.0;
  A(3, 1) = 1.5;
  A(3, 2) = -25.0;
  bl[n + 3] = -500.0;
  bu[n + 3] = bigbnd;

  /* If Trusty is to constitute at least a quarter of the final
   * portfolio, then  -5*x[0] - 0.5*x[1] + 75*x[2] >= -1000.
   */
  A(4, 0) = -5.0;
  A(4, 1) = -0.5;
  A(4, 2) = 75.0;
  bl[n + 4] = -1000.0;
  bu[n + 4] = bigbnd;

  /* Set the initial estimate of the solution.
   * This portfolio is infeasible.
   */
  x[0] = 10.0;
  x[1] = 20.0;
  x[2] = 100.0;

  /* Initialise options structure to null values. */
  /* nag_opt_init (e04xxc).
   * Initialization function for option setting
   */
  nag_opt_init(&options);
  options.inf_bound = bigbnd;

  /* Solve the problem. */
  /* nag_opt_lp (e04mfc), see above. */
  fflush(stdout);
  nag_opt_lp(n, nclin, a, tda, bl, bu, cvec,
             x, &objf, &options, &comm, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_lp (e04mfc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  /* Re-solve the problem with some additonal options. */

  printf("Re-solve problem with output of iteration results");
  printf(" suppressed and ftol = 1.0e-10.\n");

  /* Read additional options from a file. */
  print = Nag_TRUE;
  /* nag_opt_read (e04xyc).
   * Read options from a text file
   */
  fflush(stdout);
  nag_opt_read("e04mfc", optionsfile, &options, print, "stdout", &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_read (e04xyc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  /* Reset starting point */
  x[0] = 0.0;
  x[1] = 0.0;
  x[2] = 0.0;

  /* Solve the problem again. */
  /* nag_opt_lp (e04mfc), see above. */
  nag_opt_lp(n, nclin, a, tda, bl, bu, cvec,
             x, &objf, &options, &comm, &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_lp (e04mfc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

  /* Free memory allocated by nag_opt_lp (e04mfc) to pointers in options. */
  /* nag_opt_free (e04xzc).
   * Memory freeing function for use with option setting
   */
  nag_opt_free(&options, "all", &fail);
  if (fail.code != NE_NOERROR)
    {
      printf("Error from nag_opt_free (e04xzc).\n%s\n", fail.message);
      exit_status = 1;
      goto END;
    }

 END:
  NAG_FREE(x);
  NAG_FREE(cvec);
  NAG_FREE(a);
  NAG_FREE(bl);
  NAG_FREE(bu);

  return exit_status;
}