Initializing help system before first use

Folio - Examples from 'Getting Started'


Type: Portfolio optimization
Rating: 3 (intermediate)
Description: Different versions of a portfolio optimization problem.
Basic modelling and solving tasks:
  • modeling and solving a small LP problem (foliolp)
  • performing explicit initialization (folioini*)
  • 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)
  • modeling and solving QCQP problems (folioqc, requires foliocppqp.dat)
  • heuristic solution of a MIP problem (folioheur)
Advanced modeling and solving tasks:
  • enlarged version of the basic MIP model (foliomip3 with include file readfoliodata.c_, 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)
  • using the built-in infeasibility repair functionality (foliorep)
File(s): foliolp.cpp, folioinit.cpp, foliodata.cpp, foliomip1.cpp, foliomip2.cpp, folioqp.cpp, folioqc.cpp, folioheur.cpp, foliomip3.cpp, readfoliodata.c_, foliocb.cpp, foliosolpool.cpp, folioenumsol.cpp, folioinfeas.cpp, folioiis.cpp, foliorep.cpp
Data file(s): foliocpplp.dat, foliocppqp.dat, folio10.cdat

foliolp.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliolp.cpp
  ````````````````
  Modeling a small LP problem
  to perform portfolio optimization.

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define NSHARES 10                   // Number of shares
#define NRISK 5                      // Number of high-risk shares
#define NNA 4                        // Number of North-American shares

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

int main(int argc, char **argv)
{
 int s;
 XPRBprob p("FolioLP");              // Initialize a new problem in BCL
 XPRBexpr Risk,Na,Return,Cap;
 XPRBvar frac[NSHARES];              // Fraction of capital used per share

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

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

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

/* Equivalent:
 XPRBctr CRisk;
 CRisk = p.newCtr("Risk");
 for(s=0;s<NRISK;s++) CRisk.addTerm(frac[RISK[s]], 1);
 CRisk.setType(XPRB_L);
 CRisk.addTerm(1.0/3);
*/

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

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

// Upper bounds on the investment per share
 for(s=0;s<NSHARES;s++) frac[s].setUB(0.3);

// Export matrix to a file
/* p.exportProb(XPRB_MPS, "Folio");
 p.setSense(XPRB_MAXIM);
 p.exportProb(XPRB_LP, "Folio");
*/

// Disable all BCL and Optimizer message printing, except error messages
// p.setMsgLevel(1);

// Solve the problem
 p.setSense(XPRB_MAXIM);
 p.lpOptimize("");

 char *LPSTATUS[] = {"not loaded", "optimal", "infeasible",
          "worse than cutoff", "unfinished", "unbounded", "cutoff in dual",
	  "unsolved", "nonconvex"};

 cout << "Problem status: " << LPSTATUS[p.getLPStat()] << endl;

// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "%" << endl;

 return 0;
}

folioinit.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file folioinit.cpp
  ``````````````````
  Modeling a small LP problem
  to perform portfolio optimization.
  Explicit initialization.

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define NSHARES 10                   // Number of shares
#define NRISK 5                      // Number of high-risk shares
#define NNA 4                        // Number of North-American shares

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

void solveProb()
{
 int s;
 XPRBprob p("FolioLP");              // Initialize a new problem in BCL
 XPRBexpr Risk,Na,Return,Cap;
 XPRBvar frac[NSHARES];              // Fraction of capital used per share

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

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

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

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

// Spend all the capital
 for(s=0;s<NSHARES;s++) Cap += frac[s];
 p.newCtr("Cap", Cap == 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("");

 char *LPSTATUS[] = {"not loaded", "optimal", "infeasible",
          "worse than cutoff", "unfinished", "unbounded", "cutoff in dual",
	  "unsolved", "nonconvex"};

 cout << "Problem status: " << LPSTATUS[p.getLPStat()] << endl;

// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "%" << endl;
}

int main(int argc, char **argv)
{
 if(XPRB::init() != 0)
 {
   cout << "Initialization failed." << endl;
   return 1;
 }
 solveProb();
 return 0;
}

foliodata.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliodata.cpp
  ``````````````````
  Modeling a small LP problem
  to perform portfolio optimization.
  -- Data input from file --

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define DATAFILE XPRBDATAPATH "/GS/foliocpplp.dat"

#define NSHARES 10                   // Number of shares
#define NRISK 5                      // Number of high-risk shares
#define NNA 4                        // Number of North-American shares

double RET[NSHARES];                 // Estimated return in investment
char RISK[][100] = {"hardware", "theater", "telecom", "software",
                    "electronics"};  // High-risk values among shares
char NA[][100] = {"treasury", "hardware", "theater", "telecom"};
                                     // Shares issued in N.-America

XPRBindexSet SHARES;                 // Set of shares

XPRBprob p("FolioLP");               // Initialize a new problem in BCL

void readData(void)
{
 double value;
 int s;
 FILE *datafile;
 char name[100];

 SHARES=p.newIndexSet("Shares",NSHARES);  // Create the `SHARES' index set

// Read `RET' data from file
 datafile=fopen(DATAFILE,"r");
 for(s=0;s<NSHARES;s++)
 {
  XPRBreadlinecb(XPRB_FGETS, datafile, 200, "T g", name, &value);
  RET[SHARES+=name]=value;
 }
 fclose(datafile);

 SHARES.print();                     // Print out the set contents
}

int main(int argc, char **argv)
{
 int s;
 XPRBexpr Risk,Na,Return,Cap;
 XPRBvar frac[NSHARES];              // Fraction of capital used per share

// Read data from file
 readData();

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

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

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

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

// Spend all the capital
 for(s=0;s<NSHARES;s++) Cap += frac[s];
 p.newCtr("Cap", Cap == 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("");

// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << SHARES[s] << ": " << frac[s].getSol()*100 << "%" << endl;

 return 0;
}

foliomip1.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliomip1.cpp
  ``````````````````
  Modeling a small MIP problem
  to perform portfolio optimization.
   -- Limiting the total number of assets --

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 4                   // Max. number of different assets

#define NSHARES 10                 // Number of shares
#define NRISK 5                    // Number of high-risk shares
#define NNA 4                      // Number of North-American shares

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

int main(int argc, char **argv)
{
 int s;
 XPRBprob p("FolioMIP1");          // Initialize a new problem in BCL
 XPRBexpr Risk,Na,Return,Cap,Num;
 XPRBvar frac[NSHARES];            // Fraction of capital used per share
 XPRBvar buy[NSHARES];             // 1 if asset is in portfolio, 0 otherwise

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

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

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

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

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

// Limit the total number of assets
 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.setSense(XPRB_MAXIM);
 p.mipOptimize("");


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

 cout << "Problem status: " << MIPSTATUS[p.getMIPStat()] << endl;


// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "% (" << buy[s].getSol()
       << ")" << endl;

 return 0;
}

foliomip2.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliomip2.cpp
  ``````````````````
  Modeling a small MIP problem
  to perform portfolio optimization.
   -- Imposing a minimum investment per share --

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define NSHARES 10                   // Number of shares
#define NRISK 5                      // Number of high-risk shares
#define NNA 4                        // Number of North-American shares

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

int main(int argc, char **argv)
{
 int s;
 XPRBprob p("FolioSC");              // Initialize a new problem in BCL
 XPRBexpr Risk,Na,Return,Cap;
 XPRBvar frac[NSHARES];              // Fraction of capital used per share

// Create the decision variables
 for(s=0;s<NSHARES;s++)
 {
  frac[s] = p.newVar("frac", XPRB_SC, 0, 0.3);
  frac[s].setLim(0.1);
 }

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

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

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

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

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

// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "%" << endl;

 return 0;
}

folioqp.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

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

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define DATAFILE XPRBDATAPATH "/GS/foliocppqp.dat"

#define TARGET 9                   // Target yield
#define MAXNUM 4                   // Max. number of different assets

#define NSHARES 10                 // Number of shares
#define 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[NSHARES][NSHARES];      // Variance/covariance matrix of
                                   // estimated returns

int main(int argc, char **argv)
{
 int s,t;
 XPRBprob p("FolioQP");            // Initialize a new problem in BCL
 XPRBexpr Na,Return,Cap,Num,Variance;
 XPRBvar frac[NSHARES];            // Fraction of capital used per share
 XPRBvar buy[NSHARES];             // 1 if asset is in portfolio, 0 otherwise
 FILE *datafile;

// Read `VAR' data from file
 datafile=fopen(DATAFILE,"r");
 for(s=0;s<NSHARES;s++)
  XPRBreadarrlinecb(XPRB_FGETS, datafile, 200, "g ", VAR[s], NSHARES);
 fclose(datafile);

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

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

// Objective: mean variance
 for(s=0;s<NSHARES;s++)
  for(t=0;t<NSHARES;t++) Variance += VAR[s][t]*frac[s]*frac[t];
 p.setObj(Variance);                 // Set the objective function

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

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

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

// Solve the problem
 p.setSense(XPRB_MINIM);
 p.lpOptimize("");

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

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

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

// Limit the total number of assets
 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
 cout << "With a target of " << TARGET << " and at most " << MAXNUM <<
         " assets, minimum variance is " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "% (" << buy[s].getSol()
       << ")" << endl;

 return 0;
}


folioqc.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file folioqp.cpp
  ````````````````
  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. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define DATAFILE XPRBDATAPATH "/GS/foliocppqp.dat"

#define MAXVAR 0.55                // Max. allowed variance

#define NSHARES 10                 // Number of shares
#define 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[NSHARES][NSHARES];      // Variance/covariance matrix of
                                   // estimated returns

int main(int argc, char **argv)
{
 int s,t;
 XPRBprob p("FolioQC");            // Initialize a new problem in BCL
 XPRBexpr Na,Return,Cap,Variance;
 XPRBvar frac[NSHARES];            // Fraction of capital used per share
 FILE *datafile;

// Read `VAR' data from file
 datafile=fopen(DATAFILE,"r");
 for(s=0;s<NSHARES;s++)
  XPRBreadarrlinecb(XPRB_FGETS, datafile, 200, "g ", VAR[s], NSHARES);
 fclose(datafile);

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

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

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

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

// Limit variance
 for(s=0;s<NSHARES;s++)
  for(t=0;t<NSHARES;t++) Variance += VAR[s][t]*frac[s]*frac[t];
 p.newCtr(Variance <= MAXVAR);

// Solve the problem
 p.setSense(XPRB_MAXIM);
 p.lpOptimize("");

// Solution printing
 cout << "With a max. variance of " << MAXVAR << " total return is " <<
         p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  cout << s << ": " << frac[s].getSol()*100 << "%" << endl;

 return 0;
}


folioheur.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

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

  (c) 2008 Fair Isaac Corporation
      author: S.Heipcke, Aug. 2003, rev. Mar. 2011
********************************************************/

#include <iostream>
#include "xprb_cpp.h"
#include "xprs.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 4                   // Max. number of shares to be selected

#define NSHARES 10                 // Number of shares
#define NRISK 5                    // Number of high-risk shares
#define NNA 4                      // Number of North-American shares

void solveHeur();

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

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

int main(int argc, char **argv)
{
 int s;
 XPRBexpr Risk,Na,Return,Cap,Num;

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

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

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

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

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

// Limit the total number of assets
 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 problem heuristically
 p.setSense(XPRB_MAXIM);
 solveHeur();

// Solve the problem
 p.mipOptimize("");

// Solution printing
 if(p.getMIPStat()==XPRB_MIP_SOLUTION || p.getMIPStat()==XPRB_MIP_OPTIMAL)
 {
  cout << "Exact solution: Total return: " << p.getObjVal() << endl;
  for(s=0;s<NSHARES;s++)
   cout << s << ": " << frac[s].getSol()*100 << "%" << endl;
 }
 else
  cout << "Heuristic solution is optimal." << endl;

 return 0;
}

void solveHeur()
{
 XPRBbasis basis;
 int s, ifgsol;
 double solval, fsol[NSHARES],TOL;

 XPRSsetintcontrol(p.getXPRSprob(), XPRS_CUTSTRATEGY, 0);
                                   // Disable automatic cuts
 XPRSsetintcontrol(p.getXPRSprob(), XPRS_PRESOLVE, 0);
                                   // Switch presolve off
 XPRSgetdblcontrol(p.getXPRSprob(), XPRS_FEASTOL, &TOL);
                                   // Get feasibility tolerance

 p.mipOptimize("l");               // Solve the LP-relaxation
 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++)
 {
  fsol[s]=frac[s].getSol();        // Get the solution values of `frac'
  if(fsol[s] < TOL)  buy[s].setUB(0);
  else if(fsol[s] > 0.2-TOL)  buy[s].setLB(1);
 }

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

// XPRSpostsolve(p.getXPRSprob());   // 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);
  }

 p.loadBasis(basis);        /* 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 */
 basis.reset();             // No need to store the saved basis any longer
 if(ifgsol==1)
  XPRSsetdblcontrol(p.getXPRSprob(), XPRS_MIPABSCUTOFF, solval+TOL);
                            // Set the cutoff to the best known solution

}

foliomip3.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliomip3.cpp
  ``````````````````
  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 Fair Isaac Corporation
      author: S.Heipcke, May 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

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

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

#include "readfoliodata.c_"


int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3");          // Initialize a new problem in BCL
 XPRBexpr Risk,Return,Cap,Num;
 XPRBexpr *MinReg, *MaxReg, *LimSec, LinkL, LinkU;
 XPRBvar *frac;                    // Fraction of capital used per share
 XPRBvar *buy;                     // 1 if asset is in portfolio, 0 otherwise

 readdata(DATAFILE);               // Data input from file

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

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

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

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

// Diversification across industry sectors
 LimSec = new XPRBexpr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) LimSec[t] += frac[s];
  p.newCtr(LimSec[t] <= MAXSEC);
 }

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

// Limit the total number of assets
 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] <= MAXVAL*buy[s]);
  p.newCtr(frac[s] >= MINVAL*buy[s]);
 }

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


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

 cout << "Problem status: " << MIPSTATUS[p.getMIPStat()] << endl;


// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  if(buy[s].getSol()>0.5)
   cout << SHARES_n[s] << ": " << frac[s].getSol()*100 << "% (" << buy[s].getSol()
        << ")" << endl;

 return 0;
}

readfoliodata.c_
/********************************************************
  Xpress-BCL C Example Problems
  =============================

  file readfoliodata.c_
  `````````````````````
  Include file reading data for model foliomip3 
  from a text file.

  (c) 2009 Fair Isaac Corporation
      author: Y.Colombani, May 2009
********************************************************/


/****************************************************/
/* Skip empty lines & comments and find next record */
/****************************************************/
int nextrec(FILE *f,char *rec)
{
 int c;

 do
 {
  c=fgetc(f);
  if(c==EOF) return 0;
  else
   if(c=='!')
   {
    do
    {
     c=fgetc(f);
     if(c==EOF) return 0;
    }
    while(c!='\n');
   }
 } while (isspace(c));
 rec[0]=c;
 return fscanf(f,"%128s",rec+1);
}

/***************************/
/* Input a list of strings */
/***************************/
int read_str_list(FILE *f,char ***list,int *size)
{
 int n;
 char word[128];
 char *buf[MAXENTRIES];

 n=0;
 while(fscanf(f,"%128s",word)>0)
  if(strcmp(word,";")==0) break;
  else
   if(word[strlen(word)-1]==';')
   {
    word[strlen(word)-1]='\0';
    buf[n++]=strdup(word);
    break;
   }
   else
    buf[n++]=strdup(word);
   
 *size=n;
 *list=(char **)malloc(sizeof(char *)*n);
 memcpy(*list,buf,sizeof(char *)*n);
 return 0;
}

/************************/
/* Input a list of ints */
/************************/
int read_int_list(FILE *f,int **list,int *size)
{
 int n,c;
 int word;
 int buf[MAXENTRIES];

 n=0;
 while(fscanf(f,"%d",&word)>0)
  buf[n++]=word;
 
 do
 {
  c=fgetc(f);
 } while(isspace(c));

 *size=n;
 *list=(int *)malloc(sizeof(int)*n);
 memcpy(*list,buf,sizeof(int)*n);
 return 0;
}

/****************************/
/* Input a table of doubles */
/****************************/
int read_dbl_table(FILE *f,double **table,int size)
{
 int n,c;

 *table=(double *)malloc(sizeof(double)*size);
 for(n=0;n<size;n++)
  if(fscanf(f,"%lf",(*table)+n)<1) exit(1);
 
 do
 {
  c=fgetc(f);
 } while(isspace(c));

 return 0;
}

/************************************/
/* Input a sparse table of booleans */
/************************************/
int read_bool_table(FILE *f,char ***table,int nrow,int ncol)
{
 int r,c,i;
 char **tbl;

 *table=tbl=(char **)malloc(sizeof(char*)*nrow);
 tbl[0]=(char*)malloc(sizeof(char)*ncol*nrow);
 memset(tbl[0],0,sizeof(char)*ncol*nrow);
 for(r=0;r<nrow;r++)
 {
  if(r>0) tbl[r]=tbl[r-1]+ncol;
  while(fscanf(f,"%d",&i)>0)
   tbl[r][i]=1;

  do
  {
   c=fgetc(f);
  } while(isspace(c));
 }

 return 0;
}

int readdata(const char *filename)
{
 FILE *f;
 char rec[128];

 f=fopen(filename,"r");
 if(f==NULL) return 1;

 while(nextrec(f,rec)>0)
 {
  if(strcmp(rec,"SHARES:")==0 && NSHARES==0)
   read_str_list(f,&SHARES_n,&NSHARES);
  else
  if(strcmp(rec,"REGIONS:")==0 && NREGIONS==0)
   read_str_list(f,&REGIONS_n,&NREGIONS);
  else
  if(strcmp(rec,"TYPES:")==0 && NTYPES==0)
   read_str_list(f,&TYPES_n,&NTYPES);
  else
  if(strcmp(rec,"RISK:")==0 && NRISK==0)
   read_int_list(f,&RISK,&NRISK);
  else
  if(strcmp(rec,"RET:")==0 && NSHARES>0)
   read_dbl_table(f,&RET,NSHARES);
  else
  if(strcmp(rec,"LOC:")==0 && NSHARES>0 && NREGIONS>0)
   read_bool_table(f,&LOC,NREGIONS,NSHARES);
  else
  if(strcmp(rec,"SEC:")==0 && NSHARES>0 && NTYPES>0)
   read_bool_table(f,&SECT,NTYPES,NSHARES);
  else
   break;
 }

 fclose(f);
 return NSHARES<1 || NRISK<1 || NREGIONS<1 || NTYPES<1 ||
        RET==NULL || RISK==NULL || LOC==NULL || SECT==NULL;
}

void testprintout(void)
{
 int i,j;

 printf("Shares(%d):",NSHARES);
 for(i=0;i<NSHARES;i++) printf("%s ",SHARES_n[i]); printf("\n");
 printf("Regions(%d):",NREGIONS);
 for(i=0;i<NREGIONS;i++) printf("%s ",REGIONS_n[i]); printf("\n");
 printf("Types(%d):",NTYPES);
 for(i=0;i<NTYPES;i++) printf("%s ",TYPES_n[i]); printf("\n");
 printf("Risks(%d):",NRISK);
 for(i=0;i<NRISK;i++) printf("%d ",RISK[i]); printf("\n");
 printf("RET:");
 for(i=0;i<NSHARES;i++) printf("%g ",RET[i]); printf("\n");
 printf("LOC:");
 for(i=0;i<NREGIONS;i++)
 {
  for(j=0;j<NSHARES;j++)
   printf(" %d",LOC[i][j]);
  printf("\n");
 }
 printf("SECT:");
 for(i=0;i<NTYPES;i++)
 {
  for(j=0;j<NSHARES;j++)
   printf(" %d",SECT[i][j]);
  printf("\n");
 }
}


foliocb.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliocb.cpp
  ````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Defining an integer solution callback --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, May 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"
#include "xprs.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 15                  // Max. number of different assets
#define MAXRISK 1.0/3              // Max. investment into high-risk values
#define MINREG 0.2                 // Min. investment per geogr. region
#define MAXREG 0.5                 // Max. investment per geogr. region
#define MAXSEC 0.25                // Max. investment per ind. sector
#define MAXVAL 0.2                 // Max. investment per share
#define MINVAL 0.1                 // Min. investment per share

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

XPRBvar *frac;                     // Fraction of capital used per share
XPRBvar *buy;                      // 1 if asset is in portfolio, 0 otherwise

#include "readfoliodata.c_"

void XPRS_CC print_sol(XPRSprob oprob, void *vp);

int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3");          // Initialize a new problem in BCL
 XPRBexpr Risk,Return,Cap,Num;
 XPRBexpr *MinReg, *MaxReg, *LimSec, LinkL, LinkU;

 readdata(DATAFILE);               // Data input from file

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

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

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

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

// Diversification across industry sectors
 LimSec = new XPRBexpr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) LimSec[t] += frac[s];
  p.newCtr(LimSec[t] <= MAXSEC);
 }

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

// Limit the total number of assets
 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] <= MAXVAL*buy[s]);
  p.newCtr(frac[s] >= MINVAL*buy[s]);
 }

// Define an integer solution callback
 XPRSsetcbintsol(p.getXPRSprob(), print_sol, &p);

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


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

 cout << "Problem status: " << MIPSTATUS[p.getMIPStat()] << endl;

 return 0;
}

/**************************Solution printing****************************/

void XPRS_CC print_sol(XPRSprob oprob, void *vp)
{
 int num,s;
 XPRBprob *bprob;

 bprob = (XPRBprob *)vp;
 bprob->beginCB(oprob);
 XPRSgetintattrib(oprob, XPRS_MIPSOLS, &num); // Get number of the solution

 bprob->sync(XPRB_XPRS_SOL);                  // Update BCL solution values
 cout << "Solution " << num << ": Total return: " << bprob->getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  if(buy[s].getSol()>0.5)
   cout << "  " << SHARES_n[s] << ": " << frac[s].getSol()*100 << "% (" <<
           buy[s].getSol() << ")" << endl;

 bprob->endCB();
}

foliosolpool.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliosolpool.cpp
  ```````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Using the MIP solution pool --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, May 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"
#include "xprs.h"

using namespace std;
using namespace ::dashoptimization;

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

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

XPRBvar *frac;                     // Fraction of capital used per share
XPRBvar *buy;                      // 1 if asset is in portfolio, 0 otherwise
XPRBctr Return;

#include "readfoliodata.c_"

void print_sol(int num);

int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3");          // Initialize a new problem in BCL
 XPRBexpr Risk,Cap,Num,le;
 XPRBexpr *MinReg, *MaxReg, *LimSec, LinkL, LinkU;

 readdata(DATAFILE);               // Data input from file

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

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

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

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

// Diversification across industry sectors
 LimSec = new XPRBexpr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) LimSec[t] += frac[s];
  p.newCtr(LimSec[t] <= MAXSEC);
 }

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

// Limit the total number of assets
 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] <= MAXVAL*buy[s]);
  p.newCtr(frac[s] >= MINVAL*buy[s]);
 }


// Create a MIP solution pool and attach it to the problem
// (so it collects the solutions)
 XPRSmipsolpool msp;
 XPRS_msp_create(&msp);
 XPRS_msp_probattach(msp, p.getXPRSprob());

// Avoid storing of duplicate solutions (3: compare discrete variables only)
 XPRS_msp_setintcontrol(msp, XPRS_MSP_DUPLICATESOLUTIONSPOLICY, 3);

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

// Setup some resources to iterate through the solutions stored
// in the MIP solution pool
 int nSols, nCols, i;
 double *xsol;
 int *solIDs;
 XPRSgetintattrib(p.getXPRSprob(), XPRS_ORIGINALCOLS, &nCols);
 XPRS_msp_getintattrib(msp, XPRS_MSP_SOLUTIONS, &nSols);
 xsol = (double *) malloc(nCols * sizeof(double));
 solIDs = (int *) malloc(nSols * sizeof(int));

                                         // Get the solution IDs
 XPRS_msp_getsollist(msp, p.getXPRSprob(), XPRS_MSP_SOLPRB_OBJ, 1, 1,
		     nSols, solIDs, &nSols, NULL);

// Display all solutions from the pool
 for(i=0; i<nSols; i++)
 {                                       // Get the solution
  XPRS_msp_getsol(msp, solIDs[i], NULL, xsol, 0, nCols - 1, NULL);
  p.loadMIPSol(xsol, nCols, 0);          // Load the solution into BCL
  print_sol(i+1);                        // Display the solution
 }

 free(xsol);
 XPRS_msp_destroy(msp);

 return 0;
}

// Solution printing
void print_sol(int num)
{
 int s;

 cout << "Solution " << num << ": Total return: " << Return.getAct() << endl;
 for(s=0;s<NSHARES;s++)
  if(buy[s].getSol()>0.5)
   cout << "  " << SHARES_n[s] << ": " << frac[s].getSol()*100 << "% ("
        << buy[s].getSol() << ")" << endl;
}

folioenumsol.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file folioenumsol.cpp
  `````````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Using the solution enumerator --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, June 2009, rev. Jul. 2014
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"
#include "xprs.h"
#include "xprs_mse_defaulthandler.h"

using namespace std;
using namespace ::dashoptimization;

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

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

XPRBvar *frac;                     // Fraction of capital used per share
XPRBvar *buy;                      // 1 if asset is in portfolio, 0 otherwise
XPRBctr Return;

#include "readfoliodata.c_"

void print_sol(int num);

int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3");          // Initialize a new problem in BCL
 XPRBexpr Risk,Cap,Num,le;
 XPRBexpr *MinReg, *MaxReg, *LimSec, LinkL, LinkU;

 readdata(DATAFILE);               // Data input from file

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

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

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

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

// Diversification across industry sectors
 LimSec = new XPRBexpr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) LimSec[t] += frac[s];
  p.newCtr(LimSec[t] <= MAXSEC);
 }

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

// Limit the total number of assets
 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] <= MAXVAL*buy[s]);
  p.newCtr(frac[s] >= MINVAL*buy[s]);
 }


// Create a MIP solution pool & enumerator
 XPRSmipsolpool msp;
 XPRSmipsolenum mse;
 XPRS_mse_create(&mse);
 XPRS_msp_create(&msp);

// Load matrix into the Optimizer, then hand over to sol. enumerator
  p.loadMat();

// Disable heuristics to avoid duplicate solutions being stored
 XPRSsetintcontrol(p.getXPRSprob(), XPRS_HEURSTRATEGY, 0);

 int nMaxSols = 15;                 // Max. number of solutions to return

// Solve the problem
 XPRS_mse_maxim(mse, p.getXPRSprob(), msp, XPRS_mse_defaulthandler,
                NULL, &nMaxSols);

// Setup some resources to iterate through the solutions stored
// in the MIP solution pool
 int nSols, nCols, i;
 double *xsol;
 int *solIDs;
 XPRSgetintattrib(p.getXPRSprob(), XPRS_ORIGINALCOLS, &nCols);
 XPRS_mse_getintattrib(mse, XPRS_MSE_SOLUTIONS, &nSols);
 xsol = (double *) malloc(nCols * sizeof(double));
 solIDs = (int *) malloc(nSols * sizeof(int));

                                         // Get the solution IDs
 XPRS_mse_getsollist(mse, XPRS_MSE_METRIC_MIPOBJECT, 1, nSols,
                     solIDs, &nSols, NULL);

// Display all solutions from the pool
 for(i=0; i<nSols; i++)
 { 			                 // Get the solution
  XPRS_msp_getsol(msp, solIDs[i], NULL, xsol, 0, nCols - 1, NULL);
  p.loadMIPSol(xsol, nCols, 0);          // Load the solution into BCL
  print_sol(i+1);                        // Display the solution
 }

 free(xsol);
 XPRS_mse_destroy(mse);
 XPRS_msp_destroy(msp);

 return 0;
}

// Solution printing
void print_sol(int num)
{
 int s;

 cout << "Solution " << num << ": Total return: " << Return.getAct() << endl;
 for(s=0;s<NSHARES;s++)
  if(buy[s].getSol()>0.5)
   cout << "  " << SHARES_n[s] << ": " << frac[s].getSol()*100 << "% (" << buy[s].getSol()
        << ")" << endl;
}

folioinfeas.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file folioinfeas.cpp
  ````````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Infeasible model parameter values --
  -- Handling infeasibility through auxiliary variables --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, June 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 4                   // Max. number of different assets
#define MAXRISK 1.0/3              // Max. investment into high-risk values
#define MINREG 0.3                 // Min. investment per geogr. region
#define MAXREG 0.5                 // Max. investment per geogr. region
#define MAXSEC 0.15                // Max. investment per ind. sector
#define MAXVAL 0.2                 // Max. investment per share
#define MINVAL 0.1                 // Min. investment per share

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

#include "readfoliodata.c_"


int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3");          // Initialize a new problem in BCL
 XPRBctr Risk,Return,Num,*MinReg, *MaxReg, *LimSec;
 XPRBexpr le, le2, Cap, LinkL, LinkU;
 XPRBvar *frac;                    // Fraction of capital used per share
 XPRBvar *buy;                     // 1 if asset is in portfolio, 0 otherwise

 readdata(DATAFILE);               // Data input from file

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

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

// Limit the percentage of high-risk values
 le=0;
 for(s=0;s<NRISK;s++) le += frac[RISK[s]];
 Risk = p.newCtr(le <= MAXRISK);

// Limits on geographical distribution
 MinReg = new XPRBctr[NREGIONS];
 MaxReg = new XPRBctr[NREGIONS];
 for(r=0;r<NREGIONS;r++)
 {
  le=0; le2=0;
  for(s=0;s<NSHARES;s++)
   if(LOC[r][s]>0)
   {
    le += frac[s];
    le2 += frac[s];
   }
  MinReg[r] = p.newCtr(le >= MINREG);
  MaxReg[r] = p.newCtr(le2 <= MAXREG);
 }

// Diversification across industry sectors
 LimSec = new XPRBctr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  le=0;
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) le += frac[s];
  LimSec[t] = p.newCtr(le <= MAXSEC);
 }

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

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

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

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

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

 cout << "Problem status: " << MIPSTATUS[p.getMIPStat()] << endl;

 if (p.getMIPStat()==XPRB_MIP_INFEAS)
 {
  cout << "Original problem infeasible. Adding deviation variables" << endl;

  // Define deviation variables and add them to the constraints
  // to make problem solvable */
  XPRBvar devRisk, devNum, *devMinReg, *devMaxReg, *devSec;
  devRisk = p.newVar("devRisk");
  Risk -= devRisk;

  devMinReg = new XPRBvar[NREGIONS];
  devMaxReg = new XPRBvar[NREGIONS];
  for(r=0;r<NREGIONS;r++)
  {                                  /* Only allow small deviations */
   devMinReg[r] = p.newVar("devMinReg", XPRB_PL, 0, MAXREG/2);
   MinReg[r] += devMinReg[r];
   devMaxReg[r] = p.newVar("devMaxReg", XPRB_PL, 0, MAXREG/2);
   MaxReg[r] -= devMaxReg[r];
  }

  devSec = new XPRBvar[NTYPES];
  for(t=0;t<NTYPES;t++)
  {
   devSec[t] = p.newVar("devSec", XPRB_PL, 0, MAXSEC/2);
   LimSec[t] -= devSec[t];
  }

  devNum = p.newVar("devNum", XPRB_PL, 0, XPRB_INFINITY);
  Num -= devNum;


 /* Resolve the problem with penalty terms added to the objective */
  double penalty = -10;
  Return += devRisk * penalty;
  for(r=0;r<NREGIONS;r++)  Return += (devMinReg[r]+devMaxReg[r]) * penalty;
  for(t=0;t<NTYPES;t++)  Return += devSec[t] * penalty;
  Return += devNum * penalty;
  p.setObj(Return);                    /* Set the new objective function */

  p.mipOptimize("");

  if (p.getMIPStat()== XPRB_MIP_INFEAS)
  {
   cout << "No solution after relaxation" << endl;
   return 0;
  }
  else
  {
   cout << "Constraint violations:" << endl;
   cout << "  Constraint            Activity  Deviation  Bound(s)" << endl;
   printf("  Risk                    %1.2f\t  %1.2f\t  (%1.2f)\n",
          Risk.getAct()+devRisk.getSol(), devRisk.getSol(), MAXRISK);
   for(r=0;r<NREGIONS;r++)
   {
    double sumf=0;
    for(s=0;s<NSHARES;s++) if(LOC[r][s]>0) sumf+=frac[s].getSol();
    printf("  Region %-11s      %1.2f\t  %1.2f\t  (%g-%g)\n", REGIONS_n[r], sumf,
           devMaxReg[r].getSol()-devMinReg[r].getSol(),
           MINREG, MAXREG);
   }
   for(t=0;t<NTYPES;t++)
   {
    printf("  Sector %-14s   %1.2f\t  %1.2f\t  (%g)\n", TYPES_n[t],
           LimSec[t].getAct()+devSec[t].getSol(), devSec[t].getSol(),
           MAXSEC);
   }
   printf("  Number of assets        %1.2f\t  %1.2f\t  (%d)\n",
          Num.getAct()+devNum.getSol(), devNum.getSol(), MAXNUM);
  }
 }

// Solution printing
 cout << "Total return: " << p.getObjVal() << endl;
 for(s=0;s<NSHARES;s++)
  if(buy[s].getSol()>0.5)
   cout << SHARES_n[s] << ": " << frac[s].getSol()*100 << "% (" << buy[s].getSol()
        << ")" << endl;

 return 0;
}

folioiis.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file folioiis.cpp
  `````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Infeasible model parameter values --
  -- Retrieving IIS --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, June 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include "xprb_cpp.h"
#include "xprs.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 5                   // Max. number of different assets
#define MAXRISK 1.0/3              // Max. investment into high-risk values
#define MINREG 0.1                 // Min. investment per geogr. region
#define MAXREG 0.2                 // Max. investment per geogr. region
#define MAXSEC 0.1                 // Max. investment per ind. sector
#define MAXVAL 0.2                 // Max. investment per share
#define MINVAL 0.1                 // Min. investment per share

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

#include "readfoliodata.c_"


int main(int argc, char **argv)
{
 int s,r,t;
 XPRBprob p("FolioMIP3inf");       // Initialize a new problem in BCL
 XPRBctr Risk,Return,Num,*MinReg, *MaxReg, *LimSec;
 XPRBexpr le, le2, Cap, LinkL, LinkU;
 XPRBvar *frac;                    // Fraction of capital used per share
 XPRBvar *buy;                     // 1 if asset is in portfolio, 0 otherwise

 readdata(DATAFILE);               // Data input from file

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

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

// Limit the percentage of high-risk values
 le=0;
 for(s=0;s<NRISK;s++) le += frac[RISK[s]];
 Risk = p.newCtr("Risk", le <= MAXRISK);

// Limits on geographical distribution
 MinReg = new XPRBctr[NREGIONS];
 MaxReg = new XPRBctr[NREGIONS];
 for(r=0;r<NREGIONS;r++)
 {
  le=0; le2=0;
  for(s=0;s<NSHARES;s++)
   if(LOC[r][s]>0)
   {
    le += frac[s];
    le2 += frac[s];
   }
  MinReg[r] = p.newCtr(XPRBnewname("MinReg(%s)",REGIONS_n[r]), le >= MINREG);
  MaxReg[r] = p.newCtr(XPRBnewname("MaxReg(%s)",REGIONS_n[r]), le2 <= MAXREG);
 }

// Diversification across industry sectors
 LimSec = new XPRBctr[NTYPES];
 for(t=0;t<NTYPES;t++)
 {
  le=0;
  for(s=0;s<NSHARES;s++)
   if(SECT[t][s]>0) le += frac[s];
  LimSec[t] = p.newCtr(XPRBnewname("LimSec(%s)",TYPES_n[t]), le <= MAXSEC);
 }

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

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

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

// Solve the problem (LP)
 p.setSense(XPRB_MAXIM);
 p.lpOptimize("");

 if (p.getLPStat()==XPRB_LP_INFEAS)
 {
  cout << "LP infeasible. Retrieving IIS." << endl;

  int numiis = p.getNumIIS();         // Get the number of independent IIS
  cout << "Number of IIS: " << numiis << endl;

  XPRSprob op = p.getXPRSprob();     // Retrieve the Optimizer problem


/**** Obtain variable and constraint names for use in printout ****/
  int ncol, nrow, len, numc, numv, i;
  char *vnames, *cnames;
  int *viis,*ciis;
  char **vindex,**cindex;
                                  // Retrieve variable names
  XPRSgetintattrib(op, XPRS_ORIGINALCOLS, &ncol);
  XPRSgetnamelist(op, 2, NULL, 0, &len, 0, ncol-1);
                        // Get number of bytes required for retrieving names
  vnames = new char[len];
  vindex = new char*[ncol];
  XPRSgetnamelist(op, 2, vnames, len, NULL, 0, ncol-1);
  vindex[0]=vnames;
  for(i=1; i<ncol; i++) vindex[i] =vindex[i-1]+strlen(vindex[i-1])+1;

                                  // Retrieve constraint names
  XPRSgetintattrib(op, XPRS_ORIGINALROWS, &nrow);
  XPRSgetnamelist(op, 1, NULL, 0, &len, 0, nrow-1);
  cnames = new char[len];
  cindex = new char*[nrow];
  XPRSgetnamelist(op, 1, cnames, len, NULL, 0, nrow-1);
  cindex[0]=cnames;
  for(i=1; i<nrow; i++) cindex[i] =cindex[i-1]+strlen(cindex[i-1])+1;

/**** Retrieve variables and constraints contained in IIS ****/
  for(s=1;s<=numiis;s++)
  {
   XPRSgetiisdata(op, s, &numc, &numv, NULL, NULL, NULL, NULL,
                  NULL, NULL, NULL, NULL);

   ciis = new int[numc];
   viis = new int[numv];
   XPRSgetiisdata(op, s, &numc, &numv, ciis, viis, NULL, NULL,
                  NULL, NULL, NULL, NULL);
   cout << "IIS " << s << ":  " << numv << " variables, ";
   cout << numc << " constraints" << endl;
   if (numv>0)
   {
    cout << "  Variables: ";      // Print all variables in the IIS
    for(i=0;i<numv;i++) cout << vindex[viis[i]] << " ";
    cout << endl;
    delete [] viis;               // Free the array of variables
   }
   if (numc>0)
   {
    cout << "  Constraints: ";    // Print all constraints in the IIS
    for(i=0;i<numc;i++) cout << cindex[ciis[i]] << " ";
    cout << endl;
    delete [] ciis;               // Free the array of constraints
   }
  }
  delete [] vnames;
  delete [] cnames;
  delete [] vindex;
  delete [] cindex;

 }

 return 0;
}

foliorep.cpp
/********************************************************
  Xpress-BCL C++ Example Problems
  ===============================

  file foliorep.cpp
  `````````````````
  Modeling a MIP problem
  to perform portfolio optimization.

  Same model as in foliomip3.cpp.
  -- Infeasible model parameter values --
  -- Repairing infeasibilities --

  (c) 2009 Fair Isaac Corporation
      author: S.Heipcke, June 2009, rev. Mar. 2011
********************************************************/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include "xprb_cpp.h"
#include "xprs.h"

using namespace std;
using namespace ::dashoptimization;

#define MAXNUM 4                   // Max. number of different assets
#define MAXRISK 1.0/3              // Max. investment into high-risk values
#define MINREG 0.3                 // Min. investment per geogr. region
#define MAXREG 0.5                 // Max. investment per geogr. region
#define MAXSEC 0.15                // Max. investment per ind. sector
#define MAXVAL 0.2                 // Max. investment per share
#define MINVAL 0.1                 // Min. investment per share

#define DATAFILE "folio10.cdat"    // File with problem data
#define MAXENTRIES 10000


int NSHARES;                       // Number of shares
int NRISK;                         // Number of high-risk shares
int NREGIONS;                      // Number of geographical regions
int NTYPES;                        // Number of share types

double *RET;                       // Estimated return in investment
int *RISK;                         // High-risk values among shares
char **LOC;                        // Geogr. region of shares
char **SECT;                        // Industry sector of shares

char **SHARES_n;
char **REGIONS_n;
char **TYPES_n;

XPRBvar *frac;                     // Fraction of capital used per share
XPRBvar *buy;                      // 1 if asset is in portfolio, 0 otherwise

#include "readfoliodata.c_"

void print_sol_opt(XPRBprob &p);
void print_violated(vector<XPRBctr> &ctrs);

int main(int argc, char **argv)
{
  int s, r, t;
  XPRBprob p("FolioMIP3inf");       // Initialize a new problem in BCL
  XPRBctr Return, *Risk, *Num, *MinReg, *MaxReg, *LimSec;
  XPRBexpr le, le2, Cap, LinkL, LinkU;

  readdata(DATAFILE);               // Data input from file

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

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

  // allocate memory for all constraints: Risk(1), Num(1), MinReg(NREGIONS), MaxReg(NREGIONS), LimSec(NTYPES)
  vector<XPRBctr> allCtr(2 + 2 * NREGIONS + NTYPES);
  int allCtrCount = 0;
  /* init constraint pointers */
  Risk = &allCtr[allCtrCount++];
  Num = &allCtr[allCtrCount++];
  MinReg = &allCtr[allCtrCount]; allCtrCount += NREGIONS;
  MaxReg = &allCtr[allCtrCount]; allCtrCount += NREGIONS;
  LimSec = &allCtr[allCtrCount]; allCtrCount += NTYPES;


  // Limit the percentage of high-risk values
  le = 0;
  for (s = 0; s<NRISK; s++) le += frac[RISK[s]];
  *Risk = p.newCtr("Risk", le <= MAXRISK);

  // Limits on geographical distribution
  for (r = 0; r<NREGIONS; r++) {
    le = 0; le2 = 0;
    for (s = 0; s<NSHARES; s++)
    if (LOC[r][s]>0) {
      le += frac[s];
      le2 += frac[s];
    }
    MinReg[r] = p.newCtr(XPRBnewname("MinReg(%s)", REGIONS_n[r]), le >= MINREG);
    MaxReg[r] = p.newCtr(XPRBnewname("MaxReg(%s)", REGIONS_n[r]), le2 <= MAXREG);
  }

  // Diversification across industry sectors
  for (t = 0; t<NTYPES; t++) {
    le = 0;
    for (s = 0; s<NSHARES; s++)
    if (SECT[t][s]>0) le += frac[s];
    LimSec[t] = p.newCtr(XPRBnewname("LimSec(%s)", TYPES_n[t]), le <= MAXSEC);
  }

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

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

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

  // Solve the problem (LP)
  p.setMsgLevel(1);
  p.setSense(XPRB_MAXIM);
  p.lpOptimize("");

  if (p.getLPStat() == XPRB_LP_INFEAS) {
    cout << "LP infeasible. Start infeasibility repair." << endl;

    XPRSprob op = p.getXPRSprob();     // Retrieve the Optimizer problem

    // Must use the weighted infeasibility repair method since
    // only some constraints of each type may be relaxed

    /*
    lrp: (affects = and <= rows)
    ax - aux_var  = b
    ax - aux_var <= b
    grp: (affects = and >= rows)
    ax + aux_var  = b
    ax + aux_var >= b
    lbp:
    x_i + aux_var >= l
    ubp:
    x_i - aux_var <= u
    */

    int ncol, nrow, repstatus;
    double *lrp, *grp, *lbp, *ubp;
    XPRSgetintattrib(op, XPRS_ORIGINALCOLS, &ncol);
    XPRSgetintattrib(op, XPRS_ORIGINALROWS, &nrow);
    lrp = new double[nrow];
    grp = new double[nrow];
    lbp = new double[ncol];
    ubp = new double[ncol];
    memset(lrp, 0, nrow*sizeof(double));
    memset(grp, 0, nrow*sizeof(double));
    memset(lbp, 0, ncol*sizeof(double));
    memset(ubp, 0, ncol*sizeof(double));

    lrp[Risk->getRowNum()] = 1;
    for (r = 0; r<NREGIONS; r++) lrp[MaxReg[r].getRowNum()] = 1;
    for (t = 0; t<NTYPES; t++) lrp[LimSec[t].getRowNum()] = 1;
    lrp[Num->getRowNum()] = 1;
    for (r = 0; r<NREGIONS; r++) grp[MinReg[r].getRowNum()] = 1;

    char *rstat[] = { "relaxed optimum found", "relaxed problem infeasible",
      "relaxed problem unbounded", "solution nonoptimal for original objective",
      "error", "numerical instability" };

    for (double delta = 0.001; delta < 10; delta *= 10) {
      XPRSrepairweightedinfeas(op, &repstatus, lrp, grp, lbp, ubp, 'd', delta, "");
      cout << "delta = " << delta << ": Status: " << rstat[repstatus] << endl;
      if (repstatus == 0) {
        p.sync(XPRB_XPRS_SOLMIP);
        print_sol_opt(p);
        print_violated(allCtr);
      }
    }

    delete[] lrp;
    delete[] grp;
    delete[] lbp;
    delete[] ubp;
  }

  return 0;
}

void print_sol_opt(XPRBprob &p)
{
  cout << "  Total return: " << p.getObjVal() << endl;
  for (int s = 0; s<NSHARES; s++)
    if (buy[s].getSol() > 0.5)
      cout << "  " << SHARES_n[s] << " : " << frac[s].getSol() * 100 << "% (" << buy[s].getSol() << ")" << endl;
}

void print_violated(vector<XPRBctr> &ctrs)
{
  char *type = NULL;
  cout << " Violated (relaxed) constraints:" << endl;
  for (vector<XPRBctr>::iterator c = ctrs.begin(); c != ctrs.end(); c++) {
    double viol, slack = c->getSlack();
    switch (c->getType()) {
      case XPRB_E: viol = abs(slack); type = " ="; break;
      case XPRB_G: viol = slack;      type = ">="; break;
      case XPRB_L: viol = -slack;     type = "<="; break;
      default: cout << "  unexpected constraint type" << endl; continue;
    }
    if (viol > 1e-6) cout << "  " << type << " constraint " << c->getName() << " by " << -slack << endl;
  }
}