pmeanvar.gms : Mean-Variance models with variable upper and lower bounds

Description

A simple portfolio type problem with variable upper/lower
to show off strength of perspective relaxation, and also
how to make it SOCP

Contributed by Jeff Linderoth, University of Wisconsin, Madison


Small Model of Type : MIQCP


Category : GAMS Model library


Main file : pmeanvar.gms   includes :  mvdata.gdx

$title Mean-Variance Models with variable upper and lower Bounds (PMEANVAR,SEQ=380)

$onText
A simple portfolio type problem with variable upper/lower
to show off strength of perspective relaxation, and also
how to make it SOCP

Contributed by Jeff Linderoth, University of Wisconsin, Madison


O. Gunluk and J. T. Linderoth, Perspective Relaxation of Mixed
Integer Nonlinear Programs with Indicator Variables,
Mathematical Programming, Series B, 104:183-206, 2010.

Keywords: mixed integer quadratic constraint programming, portfolio optimization,
          finance
$offText

Set i 'assets';

Alias (i,j);

Parameter
   Q(i,j)   'covariance matrix'
   alpha(i) 'expected returns'
   ell(i)   'min buy-In'
   u(i)     'max buy-In';

Scalar rho 'minimum return';

$if not set isize $set isize 10
$ifE %isize%>200 $abort maximum isize is 200

Set i / 1*%isize% /;

$gdxIn mvdata
$load Q alpha ell u rho

* Produce eigenvalues and Cholesky factors of Q and Q-D
Parameter
   L(i,j)  'Cholesky of Q'
   LT(j,i) 'transpose of Cholesky of Q'
   D(i)    'diagonal extraction of Q'
   R(i,j)  'Q - D'
   M(i,j)  'Cholesky of R'
   MT(j,i) 'transpose of Cholesky of R';

executeTool.checkErrorLevel 'linalg.eigenvalue i Q D';
* Symbol D has been loaded implicitly by executeTool.checkErrorLevel. The compiler instruction
* in the next line supresses errors about presumably unassigned symbols
$onImplicitAssign

D(i)   = D('1') - 0.001;
R(i,j) = Q(i,j) - D('1')$sameas(i,j);

executeTool.checkErrorLevel 'linalg.cholesky i Q L';
option LT < L;

executeTool.checkErrorLevel 'linalg.cholesky i R M';
option MT < M;

Variable
   variance 'objective variable'
   x(i)     'purchase amounts'
   y(i)     'surrogate for x^2'
   z(i)     'indicators for purchase';

Positive Variable x, y;
Binary   Variable z;

Equation
   variance_con
   budget_con
   return_con
   vlb_con(i)
   vub_con(i);

variance_con.. variance =e= sum((i,j), Q(i,j)*x(i)*x(j));

budget_con..   sum(i,x(i)) =e= 1;

return_con..   sum(i, alpha(i)*x(i)) =g= rho;

vlb_con(i)..   x(i) =g= ell(i)*z(i);

vub_con(i)..   x(i) =l= u(i)*z(i);

variance.l = 0;

option optCr = 0;

Model basic_mv / variance_con, budget_con, return_con, vlb_con, vub_con /;

solve basic_mv minimizing variance using miqcp;

Parameter rep;
rep('basic','obj')  = variance.l;
rep('basic','secs') = basic_mv.resUsd;

Variable
   w(i) 'w = L^Tx'
   v    'objective: second rotated cone var'
   fx   'for soc';

Equation
   wdef_con(i) 'w = L^Tx'
   conedef_con '2rv >= ||w||^2';

v.lo  = 0;
fx.fx = 0.5;

* Explicit cone syntax for MOSEK
* conedef_con..    fx + v =c= sum(i, w(i));

conedef_con..      2*fx*v =g= sum(i, sqr(w(i)));

wdef_con(i)..      w(i)   =e= sum(j, LT(i,j)*x(i));

Model basic_socp_mv / budget_con, return_con, vlb_con, vub_con, conedef_con, wdef_con /;

solve basic_socp_mv minimizing v using miqcp;

rep('socp','obj')  = variance.l;
rep('socp','secs') = basic_socp_mv.resUsd;

Positive Variable t(i) '(2t_j) z_j >= x_j^2 : 2t = y: min 2Dt';

Equation
   pobj_def     'perspective objective'
   w2def_con(i) 'for w = M^Tx'
   pcone_def(i) 'for 2t_i z_i >= x_j^2';

pobj_def..     variance =e= v + sum(i, 2*D(i)*t(i));

w2def_con(i).. w(i) =e= sum(j, MT(i,j)*x(j));

* Explicit cone syntax for MOSEK
* Variable zz(i);
* Equation defzz(i);
* defzz(i)..      zz(i)        =e= z(i);
* pcone_def(i)..  t(i) + zz(i) =c= x(i);
* Model p_socp_mv / pobj_def,   w2def_con,  pcone_def, conedef_con
*                   budget_con, return_con, vlb_con,   vub_con, defzz /;

pcone_def(i).. 2*t(i)*z(i) =g= sqr(x(i));

model p_socp_mv / pobj_def, w2def_con, pcone_def, conedef_con budget_con, return_con, vlb_con, vub_con /;

solve p_socp_mv minimizing variance using miqcp;

rep('p_socp','obj')  = variance.l;
rep('p_socp','secs') = p_socp_mv.resUsd;

display rep;