/********************************************************
  Xpress-BCL Java Example Problems
  ================================

  file folioqc.java
  `````````````````
  Modeling a small QCQP problem 
  to perform portfolio optimization.
  -- Maximize return with limit on variance ---

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, July 2008, rev. Dec. 2011
********************************************************/

import com.dashoptimization.*;
import java.io.*;
import java.lang.*;

public class folioqc
{
 static final String DATAFILE = System.getProperty("XPRBDATA") +
  "/GS/foliocppqp.dat";

 static final double MAXVAR = 0.55;   /* Max. allowed variance */
 static final int NSHARES = 10;       /* Number of 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[] NA = {0,1,2,3};   /* Shares issued in N.-America */
 static double[][] VAR;               /* Variance/covariance matrix of
                                         estimated returns */

 static XPRB bcl;
 static XPRBprob p;

 private static void readData() throws IOException
 {
  int s,t;
  FileReader datafile=null;
  StreamTokenizer st=null;

  VAR = new double[NSHARES][NSHARES];

/* Read `VAR' 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) */

  for(s=0;s<NSHARES;s++)
  {
   do
   { 
    st.nextToken();
   } while(st.ttype==st.TT_EOL);    /* Skip empty lines and comment lines */
   for(t=0;t<NSHARES;t++)
   {
    if(st.ttype != st.TT_NUMBER) break;
    VAR[s][t] = st.nval;
    st.nextToken();
   }
  }
  
  datafile.close();
 }

 public static void main(String[] args)
 { 
  int s,t;
  XPRBexpr Risk,Na,Return,Cap,Num,Variance;
  XPRBvar[] frac;                  /* Fraction of capital used per share */

  bcl = new XPRB();                /* Initialize BCL */
  p = bcl.newProb("FolioQC");      /* 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", 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 */

/* Minimum amount of North-American values */
  Na = new XPRBexpr();
  for(s=0;s<NNA;s++) Na.add(frac[NA[s]]); 
  p.newCtr(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));
 
/* Limit variance */
  Variance = new XPRBexpr();
  for(s=0;s<NSHARES;s++)
    for(t=0;t<NSHARES;t++) Variance.add(frac[s].mul(frac[t]).mul(VAR[s][t])); 
  p.newCtr(Variance.lEql(MAXVAR));

/* Solve the problem */
  p.setSense(XPRB.MAXIM);
  p.lpOptimize("");
 
/* Solution printing */
  System.out.println("With a max. variance of " + MAXVAR + " total return is "
                     + p.getObjVal());
  for(s=0;s<NSHARES;s++) 
   System.out.println(s + ": " + frac[s].getSol()*100 + "%");  

/* Delete the problem */
  p.finalize();              
  p=null;
 }
} 
