FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious example

Folio - Examples from 'Getting Started'

Description
Different versions of a portfolio optimization problem.

Basic modelling and solving tasks:
  • modeling and solving a small LP problem (foliolp)
  • performing explicit initialization (folioinit)
  • data input from file, index sets (foliodata, requires foliocpplp.dat)
  • modeling and solving a small MIP problem with binary variables (foliomip1)
  • modeling and solving a small MIP problem with semi-continuous variables (foliomip2)
  • modeling and solving QP and MIQP problems (folioqp, requires foliocppqp.dat)
  • heuristic solution of a MIP problem (folioheur)
Advanced modeling and solving tasks:
  • enlarged version of the basic MIP model (foliomip3, to be used with data set folio10.cdat)
  • defining an integer solution callback (foliocb)
  • using the MIP solution pool (foliosolpool)
  • using the solution enumerator (folioenumsol)
  • handling infeasibility through deviation variables (folioinfeas)
  • retrieving IIS (folioiis, foliomiis)
  • using the built-in infeasibility repair functionality (foliorep)
Further explanation of this example: 'Getting Started with BCL' for the basic modelling and solving tasks; 'Advanced Evaluators Guide' for solution enumeration and infeasibilit handling


Source Files

Data Files





foliomip3.cs

/********************************************************
Xpress-BCL Java Example Problems
================================

file foliomip3.java
```````````````````
Modeling a MIP problem
to perform portfolio optimization.
-- Extending the problem with constraints on
  the geographical and sectorial distributions --
-- Working with a larger data set --

(c) 2009-2024 Fair Isaac Corporation
  author: S.Heipcke, Y.Colombani, rev. Mar. 2011
********************************************************/

using System;
using System.Collections;
using System.Text;
using System.IO;
using BCL;


namespace Examples {
  public class TestUGFolioMip2 {
   const String DATAFILE = "folio10.cdat";

   const int MAXNUM = 7;          /* Max. number of different assets */
   const double MAXRISK = 1.0/3;  /* Max. investment into high-risk values */
   const double MINREG = 0.2;     /* Min. investment per geogr. region */
   const double MAXREG = 0.5;     /* Max. investment per geogr. region */
   const double MAXSEC = 0.25;    /* Max. investment per ind. sector */
   const double MAXVAL = 0.2;     /* Max. investment per share */
   const double MINVAL = 0.1;     /* Min. investment per share */

   static double[] RET;              /* Estimated return in investment  */
   static int[] RISK;                /* High-risk values among shares */
   static bool[][] LOC;           /* Geogr. region of shares */
   static bool[][] SEC;           /* Industry sector of shares */

   static String[] SHARES_n;
   static String[] REGIONS_n;
   static String[] TYPES_n;

   static readonly String[] MIPSTATUS = {"not loaded", "not optimized",
                        "LP optimized", "unfinished (no solution)",
                        "unfinished (solution found)", "infeasible", "optimal",
                        "unbounded"};

   public static void Main()
   {
    try {
      readData();                     /* Read data from file */
    } catch (Exception exc){
      Console.Error.WriteLine(exc);
      Console.Error.WriteLine(Environment.StackTrace);
      return;
    }

    XPRB.init();                /* Initialize BCL */
    XPRBprob p = new XPRBprob("FolioMIP3");    /* Create a new problem in BCL */

    /* Create the decision variables */
    XPRBvar[] frac = new XPRBvar[SHARES_n.Length]; /* Fraction of capital used per share */
    XPRBvar[] buy = new XPRBvar[SHARES_n.Length]; /* 1 if asset is in portfolio, 0 otherwise */
    for(int s=0; s<SHARES_n.Length; s++)
    {
     frac[s] = p.newVar("frac", BCLconstant.XPRB_PL, 0, MAXVAL);
     buy[s] = p.newVar("buy", BCLconstant.XPRB_BV);
    }

  /* Objective: total return */
    XPRBexpr Return = new XPRBexpr();
    for(int s=0;s<SHARES_n.Length;s++) Return.add(frac[s] * RET[s]);
    p.setObj(Return);                  /* Set the objective function */

  /* Limit the percentage of high-risk values */
    XPRBexpr Risk = new XPRBexpr();
    for(int s=0;s<RISK.Length;s++) Risk.add(frac[RISK[s]]);
    p.newCtr(Risk <= MAXRISK);

  /* Limits on geographical distribution */
    XPRBexpr[] MinReg = new XPRBexpr[REGIONS_n.Length];
    XPRBexpr[] MaxReg = new XPRBexpr[REGIONS_n.Length];
    for(int r=0;r<REGIONS_n.Length;r++)
    {
     MinReg[r] = new XPRBexpr();
     MaxReg[r] = new XPRBexpr();
     for(int s=0;s<SHARES_n.Length;s++)
      if(LOC[r][s])
      {
       MinReg[r].add(frac[s]);
       MaxReg[r].add(frac[s]);
      }
      p.newCtr(MinReg[r] >= MINREG);
      p.newCtr(MaxReg[r] <= MAXREG);
    }

  /* Diversification across industry sectors */
    XPRBexpr[] LimSec = new XPRBexpr[TYPES_n.Length];
    for(int t=0;t<TYPES_n.Length;t++)
    {
     LimSec[t] = new XPRBexpr();
     for(int s=0;s<SHARES_n.Length;s++)
      if(SEC[t][s]) LimSec[t].add(frac[s]);
     p.newCtr(LimSec[t] <= MAXSEC);
    }

  /* Spend all the capital */
    XPRBexpr Cap = new XPRBexpr();
    for(int s=0;s<SHARES_n.Length;s++) Cap.add(frac[s]);
    p.newCtr(Cap == 1.0);

  /* Limit the total number of assets */
    XPRBexpr Num = new XPRBexpr();
    for(int s=0;s<SHARES_n.Length;s++) Num.add(buy[s]);
    p.newCtr(Num <= MAXNUM);

  /* Linking the variables */
    for(int s=0;s<SHARES_n.Length;s++) p.newCtr(frac[s] <= buy[s] * MAXVAL);
    for(int s=0;s<SHARES_n.Length;s++) p.newCtr(frac[s] >= buy[s] * MINVAL);

    p.exportProb(BCLconstant.XPRB_LP, "dnetmat.lp");

  /* Solve the problem */
    p.setSense(BCLconstant.XPRB_MAXIM);
    p.mipOptimize();

    Console.WriteLine("Problem status: " + MIPSTATUS[p.getMIPStat()]);

  /* Solution printing */
    Console.WriteLine("Total return: " + p.getObjVal());
    for(int s=0;s<SHARES_n.Length;s++)
     if(buy[s].getSol()>0.5)
      Console.WriteLine("  " + s + ": " + frac[s].getSol()*100 + "% (" +
       buy[s].getSol() + ")");
   }

  /***********************Data input routines***************************/

  /***************************/
  /* Input a list of strings */
  /***************************/
   private static String[] read_str_list(String data)
   {
    return data.Split();
   }

   private static Array read_list(String data, Type ty) {
    ArrayList li = new ArrayList();
    foreach(String s in data.Split()) {
      if (s == null || s == "") { continue; }
      Object value = Convert.ChangeType(s, ty);
      li.Add(value);
    }
    return li.ToArray(ty);
   }

  /************************/
  /* Input a list of ints */
  /************************/
   private static int[] read_int_list(String data)
   {
    return (int[])read_list(data, typeof(int));
   }

  /****************************/
  /* Input a table of doubles */
  /****************************/
   private static double[] read_dbl_list(String data)
   {
    return (double[])read_list(data, typeof(double));
   }

   private static bool[] read_bool_list(String data, int len) {
    bool[] bools = new bool[len];
    int[] trues = read_int_list(data);
    foreach(int t in trues) {
      bools[t] = true;
    }
    return bools;
   }

  /************************************/
  /* Input a sparse table of bools */
  /************************************/
   private static bool[][] read_bool_table(StreamReader r, int nrows, int ncols)
   {
    bool[][] lists = new bool[nrows][];
    for (int i = 0; i < nrows; i++) { lists[i] = new bool[ncols]; }

    for (int i = 0; i < nrows; i++) {
      String line = r.ReadLine();
      if (line == null) { break; }
      LineData ld = new LineData(line);
      if (ld.data == "") { break; }

      bool[] row = read_bool_list(ld.data, ncols);
      lists[i] = row;
    }
    return lists;
   }

   private class LineData {
    internal String name;
    internal String data;

    internal LineData(String line) {
      name = "";
      data = "";
      line = line.Trim();
      String[] split = line.Split(new char[] {'!'}, 2); // the comment char
      if (split.Length == 0) { return; }
      line = split[0].Trim();
      // chop into name:data pair
      split = line.Split(new char[]{':'}, 2);
      if (split.Length == 0) { return; }
      if (split.Length > 1) {
        name = split[0].Trim();
      }
      // lose trailing ';'
      data = split[split.Length - 1].Trim().TrimEnd(';').Trim();
    }
  }

   private static void readData()
   {
    using (StreamReader r = new StreamReader(DATAFILE)) {
      for(;;) {
        String line = r.ReadLine();
        if (line == null) { break; }
        LineData ld = new LineData(line);
        if (ld.name == "SHARES" && SHARES_n == null) {
          SHARES_n = read_str_list(ld.data);
        } else if (ld.name == "REGIONS" && REGIONS_n == null) {
          REGIONS_n = read_str_list(ld.data);
        } else if (ld.name == "TYPES" && TYPES_n == null) {
          TYPES_n = read_str_list(ld.data);
        } else if (ld.name == "RISK" && RISK == null) {
          RISK = read_int_list(ld.data);
        } else if (ld.name == "RET" && RET == null) {
          RET = read_dbl_list(ld.data);
        } else if (ld.name == "LOC" && SHARES_n != null && REGIONS_n != null) {
          LOC = read_bool_table(r, REGIONS_n.Length, SHARES_n.Length);
        } else if (ld.name == "SEC" && SHARES_n != null && REGIONS_n != null) {
          SEC = read_bool_table(r, TYPES_n.Length, SHARES_n.Length);
        }
      }
    }
   }
  }
}
Back to examples browserPrevious example