/********************************************************
 * Xpress-BCL Java Example Problems
 * ================================
 *
 * file folioinit2.java
 * ````````````````````
 * Modeling a small LP problem
 * to perform portfolio optimization.
 * Initialization with error handling.
 *
 * (c) 2008-2024 Fair Isaac Corporation
 * author: S.Heipcke, 2003, rev. Dec. 2011
 ********************************************************/

import com.dashoptimization.*;

public class folioinit2 {
  static final int NSHARES = 10; /* Number of shares */
  static final int NRISK = 5; /* Number of high-risk shares */
  static final int NNA = 4; /* Number of North-American shares */

  static final double[] RET = {5, 17, 26, 12, 8, 9, 7, 6, 31, 21};
  /* Estimated return in investment  */
  static final int[] RISK = {1, 2, 3, 8, 9}; /* High-risk values among shares */
  static final int[] NA = {0, 1, 2, 3}; /* Shares issued in N.-America */

  static final String[] LPSTATUS = {
    "not loaded",
    "optimal",
    "infeasible",
    "worse than cutoff",
    "unfinished",
    "unbounded",
    "cutoff in dual",
    "unsolved",
    "nonconvex"
  };

  public static void main(String[] args) {
    try (XPRB bcl = new XPRB()) {
        /* Initialize BCL */

      try (XPRBprob p = bcl.newProb("FolioLP"); /* Create a new problem in BCL */
          XPRBexprContext context =
              new XPRBexprContext() /* Release XPRBexpr instances at end of block. */) {
        int s;
        XPRBexpr Risk, Na, Return, Cap;
        XPRBvar[] frac; /* Fraction of capital used per share */

        /* Create the decision variables */
        frac = new XPRBvar[NSHARES];
        for (s = 0; s < NSHARES; s++) frac[s] = p.newVar("frac"); /*, XPRB.PL, 0, 0.3); */

        /* Objective: total return */
        Return = new XPRBexpr();
        for (s = 0; s < NSHARES; s++) Return.add(frac[s].mul(RET[s]));
        p.setObj(Return); /* Set the objective function */

        /* Limit the percentage of high-risk values */
        Risk = new XPRBexpr();
        for (s = 0; s < NRISK; s++) Risk.add(frac[RISK[s]]);
        p.newCtr("Risk", Risk.lEql(1.0 / 3));

        /* Minimum amount of North-American values */
        Na = new XPRBexpr();
        for (s = 0; s < NNA; s++) Na.add(frac[NA[s]]);
        p.newCtr("NA", Na.gEql(0.5));

        /* Spend all the capital */
        Cap = new XPRBexpr();
        for (s = 0; s < NSHARES; s++) Cap.add(frac[s]);
        p.newCtr(Cap.eql(1));

        /* Upper bounds on the investment per share */
        for (s = 0; s < NSHARES; s++) frac[s].setUB(0.3);

        /* Solve the problem */
        p.setSense(XPRB.MAXIM);
        p.lpOptimize("");

        System.out.println("Problem status: " + LPSTATUS[p.getLPStat()]);

        /* Solution printing */
        System.out.println("Total return: " + p.getObjVal());
        for (s = 0; s < NSHARES; s++) System.out.println(s + ": " + frac[s].getSol() * 100 + "%");
      }
    } catch (XPRBlicenseError e) {
      System.out.println("Initialization failed (licensing problem).");
      System.exit(1);
    } catch (XPRBerror e) {
      System.out.println("Initialization failed.");
      System.exit(1);
    }
  }
}
