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





folioqp.cs

/********************************************************
  Xpress-BCL C# Example Problems
  ==============================

  file folioqp.cs
  ```````````````
  Modeling a small QP problem
  to perform portfolio optimization.
   -- 1. QP: minimize variance
      2. MIQP: limited number of assets ---

  (c) 2008-2024 Fair Isaac Corporation
      authors: S.Heipcke, D.Brett.
********************************************************/

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


namespace Examples
{

    public class TestUGFolioQp
    {

        //Define XPRBDATAPATH to wherever you have placed the data folder; here we expect it to be same directory as compiled example.
        static string XPRBDATAPATH = Directory.GetParent(System.Reflection.Assembly.GetExecutingAssembly().Location).FullName + "/Data";
        static string DATAFILE = XPRBDATAPATH + "/GS/foliocppqp.dat";

        const int TARGET = 9;                   // Target yield
        const int MAXNUM = 4;                   // Max. number of different assets

        const int NSHARES = 10;                 // Number of shares
        const int NNA = 4;                      // Number of North-American shares

        double[] RET = {5,17,26,12,8,9,7,6,31,21};  // Estimated return in investment
        int[] NA = {0,1,2,3};              // Shares issued in N.-America
        double[,] VAR = new double[NSHARES,NSHARES];      // Variance/covariance matrix of
               // estimated returns

        public static void Main()
        {
            XPRB.init();
            int s,t;
            XPRBprob p = new XPRBprob("FolioQP");            // Initialize a new problem in BCL
            XPRBexpr Na,Return,Cap,Num;
            XPRBexpr Variance;
            XPRBvar[] frac = new XPRBvar[NSHARES];            // Fraction of capital used per share
            XPRBvar[] buy = new XPRBvar[NSHARES];             // 1 if asset is in portfolio, 0 otherwise
            FileStream file;
            StreamReader fileStreamIn;
            TestUGFolioQp TestInstance = new TestUGFolioQp();

            // Read `VAR' data from file
            file = new FileStream(DATAFILE, FileMode.Open, FileAccess.Read);
            fileStreamIn = new StreamReader(file);
            object[] outdata = new object[NSHARES];
            for (s = 0; s < NSHARES; s++)
            {
                p.XPRBreadarrline(fileStreamIn, 200, "{g} ", out outdata, NSHARES);
                for(t=0; t<NSHARES; t++)
                    TestInstance.VAR[s, t] = (double)outdata[t];
            }
            fileStreamIn.Close();
            file.Close();

            // **** First problem: unlimited number of assets ****

            // Create the decision variables
            for(s=0;s<NSHARES;s++)
                frac[s] = p.newVar("frac(" + (s+1) + ")", BCLconstant.XPRB_PL, 0, 0.3);

            // Objective: mean variance
            // A note about using operators to build expressions as in
            //    Variance += TestInstance.VAR[s,t] * (frac[s] * frac[t]);
            // These operators make it very clear what the expression looks like
            // but they also incur some overhead: each operator has to create
            // a temporary object that holds the operator's result.
            // While the overhead for binary operators is usually negligible,
            // operator+= must be used with care. By the C# language
            // specification, an expression like
            //    a += b
            // will always be evaluated as
            //    a = a + b
            // The right side of this statement usually involves creating a
            // *deep* copy of `a`. If `a` is a very big object (for example
            // a large expression) then creation of this deep copy can take
            // significant time.
            // In cases like this it is better to build expressions using
            // the `add()` or `addTerm()` member function:
            //   Variance.add(TestInstance.VAR[s,t] * frac[s] * frac[t])
            //   Variance.addTerm(TestInstance.VAR[s,t], frac[s], frac[t])
            // Either of them will modify the expression object directly and
            // will avoid the deep copy.
            Variance = new XPRBexpr();
            for(s=0;s<NSHARES;s++)
                for (t = 0; t < NSHARES; t++) Variance += TestInstance.VAR[s,t] * (frac[s] * frac[t]);
            p.setObj(Variance);                 // Set the objective function

            // Minimum amount of North-American values
            Na = new XPRBexpr();
            for (s = 0; s < NNA; s++) Na += frac[TestInstance.NA[s]];
            p.newCtr(Na >= 0.5);

            // Spend all the capital
            Cap = new XPRBexpr();
            for(s=0;s<NSHARES;s++) Cap += frac[s];
            p.newCtr(Cap == 1);

            // Target yield
            Return = new XPRBexpr();
            for (s = 0; s < NSHARES; s++) Return += TestInstance.RET[s] * frac[s];
            p.newCtr(Return >= TARGET);

            // Solve the problem
            p.setSense(BCLconstant.XPRB_MINIM);
            p.lpOptimize();              /* Solve the LP-problem */

            // Solution printing
            System.Console.WriteLine("With a target of " + TARGET + " minimum variance is " + p.getObjVal());
            for(s=0;s<NSHARES;s++)
                System.Console.WriteLine(s + ": " + frac[s].getSol()*100 + "%");

            // **** Second problem: limit total number of assets ****

            // Create the decision variables
            for(s=0;s<NSHARES;s++)
                buy[s] = p.newVar("buy(" + (s+1) + ")", BCLconstant.XPRB_BV);

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

            // Linking the variables
            for(s=0;s<NSHARES;s++) p.newCtr(frac[s] <= buy[s]);

            // Solve the problem
            p.mipOptimize();

            // Solution printing
            System.Console.WriteLine("With a target of " + TARGET + " and at most " + MAXNUM +
                                    " assets, minimum variance is " + p.getObjVal());
            for(s=0;s<NSHARES;s++)
                System.Console.WriteLine(s + ": " + frac[s].getSol()*100 + "% (" + buy[s].getSol() + ")");

            return;
        }

    }

}
Back to examples browserPrevious example