The return value doesnt satisfy my inequality constraints (I set the precision
to 1e-8, and the solution evaluates the inequality constraint to +5e-7)
In this particular case, it returns after reaching maxeval (it seems to
oscillate infinitely near the constraint boundary), but I think I saw that
happen with "xtol reached" as well. The attached code illustrates that.
thanks
Christophe
-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Steven G. Johnson
Sent: 21 November 2011 21:59
To: nlopt-discuss
Subject: Re: [NLopt-discuss] MMA method moving out of feasible region
On Nov 21, 2011, at 9:06 AM, chris wrote:
> I'm using NLOpt to solve a (strictly convex) QP problem with box,
> linear and
> quadratic inequality constraints. I tried the MMA and SLSQP methods.
> In most
> cases, they both converge to a very good solution but SLSQP always
> gives an
> answer that satisfies the inequality constraints up to required
> precision,
> whereas MMA occasionally starts erring into the infeasible region
> (despite
> starting with a feasible point). Did I misunderstand the strict
> requirement of
> feasibility of NLOpt ? (I can send an example .c file if that helps).
In general, NLopt only guarantees strict feasibility of all
evaluations for box constraints (specified explicitly as lower/upper
bounds); with other constraints, you should get something that
converges towards a feasible point (to the attainable accuracy), but
may stray outside the feasible region at intermediate steps.
MMA, in particular, has both "outer iterations" and "inner iterations"
within each outer iteration. The outer iterations are guaranteed to
be feasible (from a feasible starting point), but the inner iterations
may evaluate the function at points outside the feasible region. It
should only return the result of an outer iteration, however, i.e. a
feasible point.
When you say "MMA occasionally starts erring into the infeasible
region" are you talking about the return value of the optimization, or
just about intermediate steps prior to return? In the latter case
there is no guarantee of feasibility.
Steven
_______________________________________________
NLopt-discuss mailing list
[email protected]
http://ab-initio.mit.edu/cgi-bin/mailman/listinfo/nlopt-discuss
#include <vector>
#include <nlopt.hpp>
#include <boost/numeric/ublas/symmetric.hpp>
using std::vector;
namespace ublas = boost::numeric::ublas;
//data
double c_initialGuess [10] =
{0.00000000000000000,3.3751120535445790e-005,7.8331354472156156e-006,3.7022683684448233e-005,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.99992139306033290};
double c_Returns [10] =
{0.57534183730894939,0.75361853693561376,0.81320707241841605,0.68584281649105239,1.0867187892134469,0.73875081197658521,1.4198848137587050,0.94029934796451631,1.6158755405308778,0.0017001496300403673};
double c_PreviousWeights [10] =
{7.2310069527092565e-010,0.081617502360159688,9.7299353070326459e-010,9.6761777672132411e-010,0.093434565210364390,0.035697742262116167,0.11497477392474496,0.0027518721039319952,0.066710659656591662,0.60481288181837911};
double c_TradingCosts [10] =
{0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000};
double c_LinearConstraints [10] =
{0.24413374983701874,0.23751704919147126,0.27536692441768351,0.22589935478529985,0.25980419238619457,0.23935081313915693,0.19673766819835123,0.24464901064749398,0.32654123739732954,0.00000000000000000};
double c_MinWeights [10] =
{0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.00000000000000000,0.52354384150084243};
double c_MaxWeights [10] =
{0.094885101320799775,0.10304880883975288,0.079046830901594312,0.098721896375702167,0.092032500019005037,0.093054552061202084,0.11434947803979781,0.093898207342585319,0.066683627024280934,1.0000000000000000};
double c_maxVol = 0.13;
double c_linearMax = 0.11911403962478939;
double c_CovarMat [55] =
{0.171229891970579,0.156300524872849,0.160990718302128,0.138458782868199,0.115986075282479,0.216821131395112,0.026003182237491,0.0287274799318514,0.0434614126903358,0.145810329295916,0.06499315086136,0.0566178116838743,0.110069964275089,0.0961393900426599,0.190512091047068,0.0261232948421907,0.032368123956648,0.0455856170670122,0.0396987740240037,0.116026900129326,0.1636173408517,0.0929812467599921,0.0838528635981951,0.105241713004538,0.0706972347447946,0.0886511861868356,0.0435217368285407,0.103687318436377,0.0928591568313496,0.0814136377069847,0.130814061606889,0.0717113696849801,0.155245392269717,0.0922462030623368,0.100178247097967,0.169617682356235,0.118778573528206,0.0987988496099389,0.165512982670255,0.095543125901775,0.154449330899773,0.109798081628768,0.110266855359186,0.154274703455513,0.297844906933627,-6.38916323416339E-06,-7.40291721073104E-06,-7.21929002945255E-06,-6.70545567630249E-06,-3.5693585953525E-06,2.18812778817298E-06,-5.56016476978313E-06,-4.60194495732275E-06,-3.82704986022117E-06,3.93985877793975E-09};
class GPSOptimization
{
public:
GPSOptimization(int n,
double* covarMat,
double* returns,
double* previousWeights,
double* tradingCosts,
double* linearConstraint,
double* minWeights,
double* maxWeights,
double linearMax,
double
maxVol):myReturns(n),myPreviousWeights(n),myLinearConstraints(n),myTradingCosts(n),myMinWeights(n),myMaxWeights(n),myCovarMat(n)
{
size_t k=0;
for(size_t i=0; i<n; i++)
for(size_t j=0; j<=i; j++)
{
myCovarMat(i,j)=covarMat[k];
k++;
}
for(size_t i=0; i<n; i++)
{
myReturns[i] = returns[i];
myPreviousWeights[i]=previousWeights[i];
myTradingCosts[i]=tradingCosts[i];
myLinearConstraints[i]=linearConstraint[i];
myMinWeights[i]=minWeights[i];
myMaxWeights[i]=maxWeights[i];
}
myLinearMax = linearMax;
myMaxVol = maxVol;
}
const vector<double>& getReturns() const {return myReturns;}
const vector<double>& getPreviousWeights() const {return
myPreviousWeights;}
const vector<double>& getTradingCosts() const {return myTradingCosts;}
const vector<double>& getLinearConstraints() const {return
myLinearConstraints;}
const vector<double>& getMinWeights() const {return myMinWeights;}
const vector<double>& getMaxWeights() const {return myMaxWeights;}
double getLinearMax() const {return myLinearMax;}
double getMaxVol() const {return myMaxVol;}
const ublas::symmetric_matrix<double>& getCovarianceMatrix() const
{return myCovarMat;}
private:
vector<double>
myReturns,myPreviousWeights,myTradingCosts,myLinearConstraints,myMinWeights,myMaxWeights;
double myMaxVol,myLinearMax;
ublas::symmetric_matrix<double> myCovarMat;
};
//follow NLOpt type
double NLOptObjectiveFunction(size_t n, const double* x, double* grad, void*
f_data)
{
GPSOptimization* me = (GPSOptimization*)(f_data);
const std::vector<double>& returns = me->getReturns();
const std::vector<double>& tradingCosts = me->getTradingCosts();
const std::vector<double>& previousWeights = me->getPreviousWeights();
double res=0, sumx=0;
for(size_t i=0; i<n; ++i)
{
sumx += x[i];
res += returns[i]*x[i];
res -=
(x[i]-previousWeights[i])*(x[i]-previousWeights[i])*tradingCosts[i];
if(grad)
{
grad[i]=returns[i]-2*(x[i]-previousWeights[i])*tradingCosts[i];
}
}
double x_n = 1-sumx;
res += returns[n]*x_n;
res -=
(x_n-previousWeights[n])*(x_n-previousWeights[n])*tradingCosts[n];
if(grad)
for(size_t i=0; i<n; ++i)
grad[i] +=
-returns[n]+2*(x_n-previousWeights[n])*tradingCosts[n];
return res;
}
double NLOptVolatilityInequalityConstraints(size_t n, const double* x, double*
grad, void* f_data)
{
GPSOptimization* me = (GPSOptimization*)(f_data);
const ublas::matrix<double>& covarianceMat = me->getCovarianceMatrix();
double maxVol = me->getMaxVol();
ublas::vector<double> X(n+1);
X[n]=1;
for (size_t i=0; i<n; i++)
{
X[i]=x[i];
X[n]-=x[i];
}
ublas::vector<double> Y = ublas::prod(covarianceMat,X);
if(grad)
for(size_t i=0; i<n; i++)
grad[i]=2*(Y[i]-Y[n]);
double res=0;
for(size_t i=0; i<n; i++)
res += X[i]*Y[i];
res += X[n]*Y[n];
res-=maxVol*maxVol;
return res;
}
double NLOptLinearInequalityConstraints(size_t n, const double* x, double*
grad, void* f_data)
{
GPSOptimization* me = (GPSOptimization*)(f_data);
const std::vector<double>& linearConstraint =
me->getLinearConstraints();
double linearMax = me->getLinearMax();
double res =linearConstraint[n];
for (size_t i=0; i<n; i++)
{
res += x[i]*(linearConstraint[i]-linearConstraint[n]);
if(grad)
grad[i]=(linearConstraint[i]-linearConstraint[n]);
}
res-=linearMax;
return res;
}
double NLOptLinearEqualityConstraintsUp(size_t n, const double* x, double*
grad, void* f_data)
{
GPSOptimization* me = (GPSOptimization*)(f_data);
double floor = me->getMinWeights().back();
double res =0;
for (size_t i=0; i<n; i++)
{
res += x[i];
if(grad)
grad[i]=1.;
}
res+=floor-1;
return res;
}
double NLOptLinearEqualityConstraintsDown(size_t n, const double* x, double*
grad, void* f_data)
{
GPSOptimization* me = (GPSOptimization*)(f_data);
double cap = me->getMaxWeights().back();
double res =0;
for (size_t i=0; i<n; i++)
{
res -= x[i];
if(grad)
grad[i]=-1.;
}
res += 1-cap;
return res;
}
bool computeNLOpt(vector<double>& weights, const vector<double>& initialGuess,
const GPSOptimization* gps, double epsilon)
{
size_t n = weights.size()-1;//parametrize x_n as 1-sum(x_i) to remove
equality constraint
nlopt::opt optim(nlopt::LD_MMA,n);
if(NLOptVolatilityInequalityConstraints(n,&initialGuess[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
throw "Constraint violation in initial guess";
if(NLOptLinearInequalityConstraints(n,&initialGuess[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in initial guess";
if(NLOptLinearEqualityConstraintsUp(n,&initialGuess[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in initial guess";
if(NLOptLinearEqualityConstraintsDown(n,&initialGuess[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in initial guess";
optim.set_max_objective(&NLOptObjectiveFunction,const_cast<GPSOptimization*>(gps));
optim.add_inequality_constraint(&NLOptVolatilityInequalityConstraints,const_cast<GPSOptimization*>(gps),epsilon);
optim.add_inequality_constraint(&NLOptLinearInequalityConstraints,const_cast<GPSOptimization*>(gps),epsilon);
optim.add_inequality_constraint(&NLOptLinearEqualityConstraintsUp,const_cast<GPSOptimization*>(gps),epsilon);
optim.add_inequality_constraint(&NLOptLinearEqualityConstraintsDown,const_cast<GPSOptimization*>(gps),epsilon);
optim.set_lower_bounds(std::vector<double>(gps->getMinWeights().begin(),gps->getMinWeights().begin()+n));
optim.set_upper_bounds(std::vector<double>(gps->getMaxWeights().begin(),gps->getMaxWeights().begin()+n));
optim.set_xtol_abs(epsilon);
optim.set_maxeval(1000);
//optim.set_maxtime(10.0);
weights =
std::vector<double>(initialGuess.begin(),initialGuess.begin()+n);
double optimizedValue=0;
nlopt::result res = optim.optimize(weights,optimizedValue);
//It will sometimes return a result even when the constraints cannot be
matched. We test for that.
if(NLOptVolatilityInequalityConstraints(n,&weights[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
throw "Constraint violation in result";
if(NLOptLinearInequalityConstraints(n,&weights[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in result";
if(NLOptLinearEqualityConstraintsUp(n,&weights[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in result";
if(NLOptLinearEqualityConstraintsDown(n,&weights[0],NULL,const_cast<GPSOptimization*>(gps))>epsilon)
"Constraint violation in result";
weights.push_back(1.);
for(size_t i=0; i<n; i++)
weights.back()-=weights[i];
return (res>0 && res<5); //success without maxeval or maxtime being
reached
}
int main()
{
GPSOptimization problem(10,c_CovarMat,
c_Returns,
c_PreviousWeights,
c_TradingCosts,
c_LinearConstraints,
c_MinWeights,
c_MaxWeights,
c_linearMax,
c_maxVol);
vector<double> initialGuess(c_initialGuess,c_initialGuess+10);
vector<double> weights = initialGuess;
try
{
computeNLOpt(weights,initialGuess,&problem,1e-8);
}
catch (char* e)
{
std::cout << e;
return 0;
}
for(size_t i=0; i<10; i++)
std::cout << weights[i] << "\n";
return 0;
}
_______________________________________________
NLopt-discuss mailing list
[email protected]
http://ab-initio.mit.edu/cgi-bin/mailman/listinfo/nlopt-discuss