/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file foliodata.java
  ```````````````````
  Modeling a small LP problem 
  to perform portfolio optimization.
  -- Data input from file --

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, 2003, rev. June 2008, rev. Dec. 2011
********************************************************/

import com.dashoptimization.*;
import java.io.*;
import java.lang.*;

public class foliodata
{
 static final String DATAFILE = System.getProperty("XPRBDATA") +
  "/GS/foliocpplp.dat";
 
 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 double[] RET;               /* Estimated return in investment  */
 static final String[] RISK = {"hardware", "theater", "telecom", "software", 
                         "electronics"};  /* High-risk values among shares */
 static final String[] NA = {"treasury", "hardware", "theater", "telecom"};
                                    /* Shares issued in N.-America */

 static final String[] LPSTATUS = {"not loaded", "optimal", "infeasible", 
          "worse than cutoff", "unfinished", "unbounded", "cutoff in dual",
	  "unsolved", "nonconvex"};

 static XPRBindexSet SHARES;        /* Set of shares */ 

 static XPRB bcl;
 static XPRBprob p;
 
 private static void readData() throws IOException
 {
  int s;
  FileReader datafile=null;
  StreamTokenizer st=null;

  SHARES=p.newIndexSet("Shares",NSHARES);  /* Create the `SHARES' index set */
  RET = new double[NSHARES];

 /* Read `RET' data from file */
  datafile=new FileReader(DATAFILE);   /* Open the data file */
  st=new StreamTokenizer(datafile); /* Initialize the stream tokenizer */
  st.commentChar('!');              /* Use the character '!' for comments */
  st.eolIsSignificant(true);        /* Return end-of-line character */
  st.parseNumbers();                /* Read numbers as numbers (not strings) */

  do                                /* Read data file and fill the index sets */
  {
   do
   { 
    st.nextToken();
   } while(st.ttype==st.TT_EOL);    /* Skip empty lines and comment lines */
   if(st.ttype != st.TT_WORD && st.ttype != '"') break; 
   s=SHARES.addElement(st.sval);
   if(st.nextToken() != st.TT_NUMBER) break;
   RET[s] = st.nval;
  } while( st.nextToken() == st.TT_EOL );
  
  datafile.close();
 
  SHARES.print();                   /* Print out the set contents */ 
 }

 public static void main(String[] args)
 { 
  int s;
  XPRBexpr Risk,Na,Return,Cap;
  XPRBvar[] frac;                   /* Fraction of capital used per share */

  bcl = new XPRB();                 /* Initialize BCL */
  p = bcl.newProb("FolioLP");       /* Create a new problem in BCL */

  try
  {
   readData();                      /* Read data from file */
  }
  catch(IOException e)
  {
   System.err.println(e.getMessage());
   System.exit(1);
  }

/* Create the decision variables */
  frac = new XPRBvar[NSHARES];
  for(s=0;s<NSHARES;s++) frac[s] = p.newVar("frac");
 
/* 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[SHARES.getIndex(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[SHARES.getIndex(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(/*SHARES.getIndexName(s) +*/ ": " + frac[s].getSol()*100 + "%");   

/* Delete the problem */
  p.finalize();              
  p=null;
 }
} 
