sharpe = function(G, rT, w0, rf) {
  # Computes the largest Sharpe ratio (assuming no short-selling), 
  #
  #   minimize    f
  #   subject to  (r-e*rf)'*y = 1
  #               G*y  = g,  ||g||_2 <= f
  #               sum(y) = t*sum(w0)
  #               t >= 0
  #               y >= 0
  #
  # or equivalently 
  # 
  #   minimize      f
  #   subject to  [ (r-e*rf)'  0   0      0      ] [ y ]   [ 1 ] 
  #               [    G       0  -I      0      ]*[ f ] = [ 0 ] 
  #               [    e'      0   0   -sum(w0)  ] [ g ]   [ 0 ]    
  #                                                [ t ]
  #                 t     >= 0
  #                 y     >= 0
  #               ||g||_2 <= f

  n <- length(rT);
  p <- nrow(G);

  prob <- list(sense="minimize");
  prob$A <- rBind(
    cBind(rT-rf, Matrix(0,ncol=1+p+1)),
    cBind(G, Matrix(0,nrow=p), (-1)*Diagonal(p), Matrix(0,nrow=p)),
    cBind(Matrix(1,ncol=n), Matrix(0,ncol=1+p), -sum(w0))
  )
  prob$c <- c(rep(0,n), 1, rep(0,p+1));
  prob$cones <- cBind(
    list('MSK_CT_QUAD', (n+1):(n+p+1))
  );

  b <- c(1, rep(0,p+1));
  prob$bc <- rBind(b,b);
  prob$bx <- rBind(c(rep(0,n),rep(-Inf,1+p),0), rep(Inf,n+1+p+1));

  res  <- mosek(prob);
  y    <- res$sol$itr$xx[1:n];
  f    <- res$sol$itr$xx[n+1];
  g    <- res$sol$itr$xx[n+1+(1:p)];
  t    <- res$sol$itr$xx[n+1+p+1];
  x    <- y/t - w0;
  risk <- f/t;
  ret  <- ( rT%*%(x+w0) )[1];
  return( list(x=x, risk=risk, ret=ret) );
}
