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





folioheur.cs

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

  file folioheur.cs
  `````````````````
  Modeling a small MIP problem 
  to perform portfolio optimization.
   -- Heuristic solution --

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

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


namespace Examples
{
    public class TestUGFolioHeur
    {
        const int MAXNUM = 4;          // Max. number of shares to be selected

        const int NSHARES = 10;        // Number of shares
        const int NRISK = 5;           // Number of high-risk shares
        const int NNA = 4;             // Number of North-American shares

    // Estimated return in investment
        double[] RET = {5,17,26,12,8,9,7,6,31,21};  
        
        // High-risk values among shares
        int[] RISK = {1,2,3,8,9};          
        
        // Shares issued in N.-America
        int[] NA = {0,1,2,3};              

        // Initialize a new problem in BCL
        XPRBprob p = new XPRBprob("FolioMIPHeur");        
        
        // Fraction of capital used per share
        XPRBvar[] frac = new XPRBvar[NSHARES];             
        
        // 1 if asset is in portfolio, 0 otherwise
        XPRBvar[] buy = new XPRBvar[NSHARES];              

        public static void Main()
        {
            XPRB.init();
            int s;
            XPRBexpr Risk,Na,Return,Cap,Num;
            TestUGFolioHeur TestInstance = new TestUGFolioHeur();

            // Create decision variables (including upper bounds for `frac')
            for(s=0;s<NSHARES;s++) 
            {
                TestInstance.frac[s] = 
                    TestInstance.p.newVar("frac", BCLconstant.XPRB_PL, 0, 0.3);
                TestInstance.buy[s] = 
                    TestInstance.p.newVar("buy", BCLconstant.XPRB_BV);
            } 

            // Objective: total return
            Return = new XPRBexpr();
            for (s = 0; s < NSHARES; s++) 
                Return += TestInstance.RET[s] * TestInstance.frac[s];
            
            // Set the objective function
            TestInstance.p.setObj(TestInstance.p.newCtr("Objective", Return));

            // Limit the percentage of high-risk values
            Risk = new XPRBexpr();
            for (s = 0; s < NRISK; s++) 
                Risk += TestInstance.frac[TestInstance.RISK[s]];
            TestInstance.p.newCtr(Risk <= 1.0 / 3);

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

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

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

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

            // Solve problem heuristically
            TestInstance.solveHeur();

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

            // Solution printing
            if (TestInstance.p.getMIPStat() == 4 || 
                TestInstance.p.getMIPStat() == 6)
            {
                System.Console.WriteLine("Exact solution: Total return: " +
                              TestInstance.p.getObjVal());
                for(s=0;s<NSHARES;s++)
                    System.Console.WriteLine(s + ": " + 
                            TestInstance.frac[s].getSol() * 100 + "%");
            }    
            else
                System.Console.WriteLine("Heuristic solution is optimal.");

            return;
        } 

        void solveHeur()
        {
            XPRBbasis basis;
            int s, ifgsol;
            double solval=0, TOL;
            double[] fsol = new double[NSHARES];
            XPRSprob xprsp = p.getXPRSprob();

            xprsp.CutStrategy = 0;
            // Disable automatic cuts

            xprsp.Presolve = 0;
            // Switch presolve off

            TOL = xprsp.FeasTol;
            // Get feasibility tolerance

            p.setSense(BCLconstant.XPRB_MAXIM);
            p.lpOptimize();              /* Solve the LP-problem */
            basis=p.saveBasis();              // Save the current basis

            // Fix all variables `buy' for which `frac' is at 0 or at a
            // relatively large value
            for(s=0;s<NSHARES;s++)
            {
                // Get the solution values of `frac'
                fsol[s]=frac[s].getSol();        
                if(fsol[s] < TOL)  
                    buy[s].setUB(0);
                else if(fsol[s] > 0.2-TOL)  
                    buy[s].setLB(1);
            }

            p.mipOptimize();                     // Solve the MIP-problem
            
            
            // If an integer feas. solution was found...
            ifgsol=0;            
            if(p.getMIPStat()==4 || p.getMIPStat()==6)
            {                                 
                ifgsol=1;
                
                // ...get the value of the best solution
                solval=p.getObjVal();            
                System.Console.WriteLine("Heuristic solution: Total return: " +
                              p.getObjVal());
                for(s=0;s<NSHARES;s++) 
                    System.Console.WriteLine(s + ": " + frac[s].getSol()*100 +
                                     "%");  
            }

            xprsp.InitGlobal();// Re-initialize the global search

            // Reset variables to their original bounds
            for(s=0;s<NSHARES;s++)
                if((fsol[s] < TOL) || (fsol[s] > 0.2-TOL))
                {
                    buy[s].setLB(0);
                    buy[s].setUB(1);
                }

            /* Load the saved basis: bound changes are
            immediately passed on from BCL to the
            Optimizer if the problem has not been modified
            in any other way, so that there is no need to 
            reload the matrix */
            p.loadBasis(basis);        

             // No need to store the saved basis any longer
            basis.reset();

            // Set the cutoff to the best known solution
            if (ifgsol == 1)
                xprsp.MIPAbsCutoff = solval + TOL;

        } 

    }

}
Back to examples browserPrevious example