Global solution of polynomial programs
This
example requires the solver PENBMI as a
local nonlinear solver (fmincon
is sufficient for the first examples).
Moreover, the examples below are all coded to use PENSDP
and GLPK for solving the relaxations.
Global solutions! Well, almost... don't expect too much at this stage.
The functionality described here is under development. The code
is fairly robust on small bilinear and indefinite quadratic
optimization problems, and a couple of small problems
with bilinear matrix inequalities have been solved successfully.
The algorithm is based on a simple spatial branch and bound strategy,
using McCormick's convex envelopes for bounding bilinear terms. In
addition to this, LP-based bound tightening can be applied iteratively to
improve
variable bounds. Relaxed problems are solved using either an LP solver or an SDP
solver, depending on the problem, while upper bounds are found using the
local solver PENBMI. A more detailed
description of the algorithm will be presented in the future.
Options
In the examples below, we are mainly using the default settings when solving
the problem, but there are several options that can be changed to
alter the computations. The most important are
sdpsettings('bmibnb.roottight',[0|1]) |
Improve variable bounds at root-node by performing bound
strengthening based on the full relaxed model (Can be very expensive,
but lead to improved branching) |
sdpsettings('bmibnb.lpreduce',[0|1]) |
Improve variable bounds in all nodes by performing bound
strengthening using only the scalar constraints (including scalar cut
constraints) in the model (Can be very expensive, but lead to
improved branching, in particular for semidefinite problems) |
sdpsettings('bmibnb.lowersolver', solvertag) |
Solver for relaxed problems. |
sdpsettings('bmibnb.uppersolver', solvertag) |
Local solver for computing upper bounds. |
sdpsettings('bmibnb.lpsolver', solvertag) |
LP solver for bound strengthening
(only used if bmibnb.lpreduce is set to 1) |
sdpsettings('bmibnb.numglobal', [int]) |
A major computational burden along the branching process is to
solver the upper bound problems using a local nonlinear solver. By
setting this value to a finite value, the local solver will no
longer be used when the upper bound has been improved numglobal times.
This option is useful if you believe your local solver quickly gives
globally optimal solutions. It can also be useful if you have a
feasible solution and just want to compute a gap. In this case, use
the usex0 option and set numglobal to 0. |
Nonconvex quadratic programming
The first example is a problem with a concave quadratic constraint (this
is the example addressed in the moment
relaxation section). Three different optimization problems are solved
during the branching: Upper bounds using a local nonlinear solver (bmibnb.uppersolver ),
lower bounds (bmibnb.lowersolver ) and bound tightening using
linear programming (bmibnb.lpsolver ).
clear all
x1 = sdpvar(1,1);
x2 = sdpvar(1,1);
x3 = sdpvar(1,1);
p = -2*x1+x2-x3;
F = set(x1*(4*x1-4*x2+4*x3-20)+x2*(2*x2-2*x3+9)+x3*(2*x3-13)+24>0);
F = F + set(4-(x1+x2+x3)>0);
F = F + set(6-(3*x2+x3)>0);
F = F + set(x1>0);
F = F + set(2-x1>0);
F = F + set(x2>0);
F = F + set(x3>0);
F = F + set(3-x3>0);
options = sdpsettings('bmibnb.uppersolver','penbmi','bmibnb.lowersolver','glpk');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2);
solvesdp(F,p,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : glpk
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : Inf NaN -6.000E+000 2
2 : Inf NaN -6.000E+000 3
3 : -4.000E+000 40.00 -6.000E+000 4 Improved solution
4 : -4.000E+000 40.00 -6.000E+000 3 Infeasible
5 : -4.000E+000 37.98 -5.899E+000 4 Poor bound
6 : -4.000E+000 37.98 -5.899E+000 5
7 : -4.000E+000 25.80 -5.290E+000 6
8 : -4.000E+000 25.80 -5.290E+000 5 Infeasible
9 : -4.000E+000 7.08 -4.354E+000 4 Infeasible
10 : -4.000E+000 7.08 -4.354E+000 3 Infeasible
11 : -4.000E+000 0.06 -4.003E+000 4
+ 11 Finishing. Cost: -4 Gap: 0.06486%
|
The second example is a slightly larger problem indefinite quadratic
programming problem. The problem is easily solved to a gap of
less than 1%.
clear all
x1 = sdpvar(1,1);
x2 = sdpvar(1,1);
x3 = sdpvar(1,1);
x4 = sdpvar(1,1);
x5 = sdpvar(1,1);
x6 = sdpvar(1,1);
p = -25*(x1-2)^2-(x2-2)^2-(x3-1)^2-(x4-4)^2-(x5-1)^2-(x6-4)^2;
F = set((x3-3)^2+x4>4)+set((x5-3)^2+x6>4);
F = F + set(x1-3*x2<2)+set(-x1+x2<2);
F = F + set(x1-3*x2 <2)+set(x1+x2>2);
F = F + set(6>x1+x2>2);
F = F + set(1<x3<5) + set(0<x4<6)+set(1<x5<5)+set(0<x6<10)+set(x1>0)+set(x2>0);
options = sdpsettings('bmibnb.uppersolver','penbmi','bmibnb.lowersolver','glpk');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2,'solver','bmibnb');
solvesdp(F,p,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : glpk
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : Inf NaN -3.130E+002 2
2 : -3.100E+002 0.96 -3.130E+002 3 Improved solution
+ 2 Finishing. Cost: -310 Gap: 0.96463%
|
Quadratic equality constraints can also be dealt with. This can be used
for, e.g., boolean programming.
n = 10;
x = sdpvar(n,1);
Q = randn(n,n);Q = Q*Q'/norm(Q)^2;
c = randn(n,1);
objective = x'*Q*x+c'*x;
F = set(x.*(x-1)==0) + set(0<x<1);
options = sdpsettings('bmibnb.uppersolver','penbmi','bmibnb.lowersolver','glpk');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2,'solver','bmibnb');
solvesdp(F,objective,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : glpk
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -2.967E+000 0.00 -2.967E+000 2 Improved solution
+ 1 Finishing. Cost: -2.9671 Gap: 2.5207e-009%
|
Nonconvex polynomial programming
The global solver in YALMIP can only solve bilinear programs, but
a pre-processor is capable of transforming higher order problems to
bilinear programs. As an example, the variable x3y2
will be replaced with the the variable w and the constraints
w == uv, u == zx, z == x2, v == y2.
The is done automatically if the global solver, or PENBMI,
is called with a higher order polynomial problem. Note that this
conversion is rather inefficient, and only very small problems can
be addressed using this simple approach. Additionally, this module
has not been tested in any serious sense.
sdpvar x y
F = set(x^3+y^5 < 5) + set(y > 0);
F = F + set(-100 < [x y] < 100) % Always bounded domain
solvesdp(F,-x,options)
* Starting YALMIP bilinear branch & bound.
* Lower solver : glpk
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : Inf NaN -2.990E+001 2
2 : Inf NaN -2.990E+001 1 Infeasible
3 : Inf NaN -2.763E+001 2
4 : Inf NaN -2.763E+001 3
5 : Inf NaN -1.452E+001 4
6 : Inf NaN -1.452E+001 5
7 : -1.710E+000 171.54 -6.359E+000 4 Improved solution
8 : -1.710E+000 171.54 -6.359E+000 3 Infeasible
9 : -1.710E+000 127.11 -5.155E+000 4 Poor bound
10 : -1.710E+000 127.11 -5.155E+000 3 Infeasible
11 : -1.710E+000 0.00 -1.710E+000 2 Infeasible
+ 11 Finishing. Cost: -1.71 Gap: 1.247e-005%
|
Nonconvex semidefinite programming
The following problem is a classical BMI problem
yalmip('clear')
x = sdpvar(1,1);
y = sdpvar(1,1);
t = sdpvar(1,1);
A0 = [-10 -0.5 -2;-0.5 4.5 0;-2 0 0];
A1 = [9 0.5 0;0.5 0 -3 ; 0 -3 -1];
A2 = [-1.8 -0.1 -0.4;-0.1 1.2 -1;-0.4 -1 0];
K12 = [0 0 2;0 -5.5 3;2 3 0];
F = lmi(x>-0.5)+lmi(x<2) + lmi(y>-3)+lmi(y<7);
F = F + lmi(A0+x*A1+y*A2+x*y*K12-t*eye(3)<0);
options = sdpsettings('bmibnb.lowersolver','pensdp','bmibnb.uppersolver','penbmi');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2,'solver','bmibnb');
solvesdp(F,t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -9.565E-001 2.22 -1.000E+000 2 Improved solution
2 : -9.565E-001 2.22 -1.000E+000 1 Infeasible
3 : -9.565E-001 2.22 -1.000E+000 2
4 : -9.565E-001 2.22 -1.000E+000 3
5 : -9.565E-001 0.24 -9.613E-001 2 Infeasible
+ 5 Finishing. Cost: -0.95653 Gap: 0.24126%
|
The constrained LQ problem in the section Local BMIs
can actually easily be solved to global optimality in just a couple of
iterations. For the global code to work, global lower and upper and bound on
all complicating variables (involved in nonlinear terms) must be supplied, either explicitly or implicitly in the linear
constraints. This was the case for all problems above. In this example, the variable
K is already bounded in
the original problem, but the elements in P have to be bounded
artificially.
yalmip('clear')
A = [-1 2;-3 -4];B = [1;1];
P = sdpvar(2,2);
K = sdpvar(1,2);
F = set(P>0)+set((A+B*K)'*P+P*(A+B*K) < -eye(2)-K'*K);
F = F + set(K<0.1)+set(K>-0.1);
F = F + set(1000> P(:)>-1000)
options = sdpsettings('bmibnb.lowersolver','pensdp','bmibnb.uppersolver','penbmi');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2,'solver','bmibnb');
solvesdp(F,trace(P),options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : 4.834E-001 17.70 2.209E-001 2 Improved solution
2 : 4.834E-001 17.70 2.209E-001 1 Infeasible
3 : 4.834E-001 1.93 4.548E-001 2
4 : 4.834E-001 1.93 4.548E-001 1 Infeasible
5 : 4.834E-001 0.25 4.797E-001 2
+ 5 Finishing. Cost: 0.48341 Gap: 0.25032%
|
Beware, the BMI solver is absolutely not that efficient in general,
this was just a lucky case. Here is the decay-rate
example instead (with some additional constraints on the elements
in P to bound the feasible set).
yalmip('clear');
A = [-1 2;-3 -4];
t = sdpvar(1,1);
P = sdpvar(2,2);
F = set(P>eye(2))+set(A'*P+P*A < -2*t*P);
F = F + set(-1e4 < P(:) < 1e4) + set(100 > t > 0) ;
options = sdpsettings('bmibnb.lowersolver','pensdp','bmibnb.uppersolver','penbmi');
options = sdpsettings(options,'solver','bmibnb','bmibnb.lpsolver','glpk');
options = sdpsettings(options,'verbose',2,'solver','bmibnb');
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : Inf NaN -9.965E+001 2
2 : -2.500E+000 2775.83 -9.965E+001 3 Improved solution
3 : -2.500E+000 2721.00 -9.773E+001 4
4 : -2.500E+000 2721.00 -9.773E+001 3 Infeasible
5 : -2.500E+000 2634.59 -9.471E+001 4
6 : -2.500E+000 2634.59 -9.471E+001 3 Infeasible
7 : -2.500E+000 2577.61 -9.272E+001 4
8 : -2.500E+000 2577.61 -9.272E+001 3 Infeasible
9 : -2.500E+000 2501.03 -9.004E+001 4
10 : -2.500E+000 2501.03 -9.004E+001 3 Infeasible
...
94 : -2.500E+000 4.30 -2.650E+000 49
95 : -2.500E+000 0.47 -2.516E+000 50
+ 95 Finishing. Cost: -2.5 Gap: 0.46843%
|
The linear relaxations give very poor lower bounds on this problem,
leading to poor convergence of the branching process. However, for this
particular problem, the reason is easy to find. The original BMI is
homogeneous w.r.t P, and to guarantee a somewhat reasonable
solution, we artificially added the constraint P≥I.
A better model is obtained if we instead fix the trace of P. This will
make the feasible set w.r.t P much smaller, but the problems are
equivalent. Note also that we no longer need any artificial constraints
on the elements in P.
F = set(P>0)+set(A'*P+P*A < -2*t*P) + set(100 > t > 0) ;
F = F + set(trace(P)==1);
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -2.500E+000 1396.51 -5.138E+001 2 Improved solution
2 : -2.500E+000 1396.51 -5.138E+001 1 Infeasible
3 : -2.500E+000 1.41 -2.549E+000 2
4 : -2.500E+000 1.41 -2.549E+000 1 Infeasible
5 : -2.500E+000 0.17 -2.506E+000 2
+ 5 Finishing. Cost: -2.5 Gap: 0.1746%
|
For this problem, we can easily find a very efficient additional cutting
plane. The
decay-rate BMI together with the constant trace on P implies trace(ATP+PA)≤-2t.
Adding this cut reduce the number of iterations needed.
F = set(P>0)+set(A'*P+P*A < -2*t*P) + set(100 > t > 0);
F = F + set(trace(P)==1);
F = F + set(trace(A'*P+P*A)<-2*t);
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -2.500E+000 26.60 -3.431E+000 2 Improved solution
2 : -2.500E+000 26.60 -3.431E+000 3
3 : -2.500E+000 0.55 -2.519E+000 2 Infeasible
+ 3 Finishing. Cost: -2.5 Gap: 0.5461%
|
A Schur complement on the decay-rate BMI gives us yet another cut
which improves the node relaxation even more.
F = set(P>0)+set(A'*P+P*A < -2*t*P) + set(100 > t > 0) ;
F = F + set(trace(P)==1);
F = F + set(trace(A'*P+P*A)<-2*t)
F = F + set([-A'*P-P*A P*t;P*t P*t/2]);
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -2.500E+000 17.84 -3.124E+000 2 Improved solution
2 : -2.500E+000 17.84 -3.124E+000 3
3 : -2.500E+000 0.55 -2.519E+000 2 Infeasible
+ 3 Finishing. Cost: -2.5 Gap: 0.55275%
|
By adding valid cuts, the relaxations are possibly tighter, leading to
better lower bounds. A problem however is that we add additional
burden to the local solver used for the upper bounds. The additional
cuts are redundant for the local solver, and most likely detoriate the
performance. To avoid this, cuts can be exlicitely specified by using
the command cut.
Constraints defined using this command (instead of
set) will only be used
in the solution of relaxations, and omitted when the local solver is
called.
F = set(P>0)+set(A'*P+P*A < -2*t*P) + set(100 > t > 0) ;
F = F + set(trace(P)==1);
F = F + cut(trace(A'*P+P*A)<-2*t);
F = F + cut([-A'*P-P*A P*t;P*t P*t/2]);
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : penbmi
Node Upper Gap(%) Lower Open
1 : -2.500E+000 17.84 -3.124E+000 2 Improved solution
2 : -2.500E+000 17.84 -3.124E+000 3
3 : -2.500E+000 0.55 -2.519E+000 2 Infeasible
+ 3 Finishing. Cost: -2.5 Gap: 0.55275%
|
Upper bounds were obtained above by solving the BMI locally using
PENBMI. If no local BMI solver is available, an alternative is to
check if the relaxed solution is a feasible solution. If so,
the upper bound can be updated. This scheme
can be obtained by specifying 'none' as the upper bound solver.
options = sdpsettings(options,'bmibnb.uppersolver','none');
F = set(P>0)+set(A'*P+P*A < -2*t*P) + set(100 > t > 0) ;
F = F + set(trace(P)==1);
F = F + cut(trace(A'*P+P*A)<-2*t);
F = F + cut([-A'*P-P*A P*t;P*t P*t/2]);
solvesdp(F,-t,options);
* Starting YALMIP bilinear branch & bound.
* Lower solver : pensdp
* Upper solver : none
Node Upper Gap(%) Lower Open
1 : Inf NaN -3.124E+000 2
2 : Inf NaN -3.124E+000 3
3 : -9.045E-001 104.47 -2.894E+000 4 Improved solution
4 : -9.045E-001 104.47 -2.894E+000 5
5 : -1.467E+000 52.43 -2.761E+000 4 Improved solution
6 : -1.467E+000 52.43 -2.761E+000 5
7 : -1.831E+000 29.87 -2.677E+000 4 Improved solution
8 : -1.831E+000 29.87 -2.677E+000 5
9 : -2.071E+000 17.77 -2.616E+000 4 Improved solution
10 : -2.071E+000 17.77 -2.616E+000 5
11 : -2.229E+000 10.46 -2.567E+000 4 Improved solution
12 : -2.229E+000 10.46 -2.567E+000 5
13 : -2.332E+000 5.70 -2.522E+000 4 Improved solution
14 : -2.332E+000 5.70 -2.522E+000 5
15 : -2.397E+000 3.25 -2.508E+000 4 Improved solution
16 : -2.397E+000 3.25 -2.508E+000 5
17 : -2.435E+000 2.01 -2.504E+000 4 Improved solution
18 : -2.435E+000 2.01 -2.504E+000 5
19 : -2.459E+000 1.25 -2.503E+000 4 Improved solution
20 : -2.459E+000 1.25 -2.503E+000 5
21 : -2.478E+000 0.70 -2.502E+000 4 Improved solution
+ 21 Finishing. Cost: -2.4776 Gap: 0.69631%
|
More examples can be found in
yalmipdemo.
The global
branch and bound algorithm will hopefully be improved upon
significantly in future releases. This includes both algorithmic
improvements and code optimization. If you have any ideas, you are welcome to contribute. |