⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bmibnb.m

📁 求解线性矩阵不等式简单方便--与LMI工具箱相比
💻 M
字号:
function output = bmibnb(p)
%BMIBNB          Branch-and-bound scheme for bilinear programs
%
% BMIBNB is never called by the user directly, but is called by YALMIP from
% SOLVESDP, by choosing the solver tag 'bmibnb' in sdpsettings
%
% The behaviour of BMIBNB can be altered using the fields in the field
% 'bmibnb' in SDPSETTINGS
%
% bmibnb.lowersolver    - Solver for lower bound [solver tag ('')]
% bmibnb.uppersolver    - Solver for upper bound [solver tag ('')]
% bmibnb.lpsolver       - Solver for LP bound tightening [solver tag ('')]
% bmibnb.branchmethod   - Branch strategy ['maxvol' | 'best' ('best')]
% bmibnb.branchrule     - Branch position ['omega' | 'bisect' ('omega')]
% bmibnb.lpreduce       - Improve variable bounds using LP [ real [0,1] (0 means no reduction, 1 means all variables)
% bmibnb.lowrank        - Partition variables into two disjoint sets and branch on smallest [ 0|1 (0)]
% bmibnb.target         - Exit if upper bound<target [double (-inf)]
% bmibnb.roottight      - Improve variable bounds in root using full problem [ 0|1 (1)]
% bmibnb.vartol         - Cut tree when x_U-x_L < vartol on all branching variables
% bmibnb.relgaptol      - Tolerance on relative objective error (UPPER-LOWER)/(1+|UPPER|) [real (0.01)]
% bmibnb.absgaptol      - Tolerance on objective error (UPPER-LOWER) [real (0.01)]
% bmibnb.pdtol          - A number is declared non-negative if larger than...[ double (-1e-6)]
% bmibnb.eqtol          - A number is declared zero if abs(x) smaller than...[ double (1e-6)]
% bmibnb.maxiter        - Maximum number nodes [int (100)]
% bmibnb.maxtime        - Maximum CPU time (sec.) [int (3600)]

% Author Johan L鰂berg
% $Id: bmibnb.m,v 1.28 2006/11/30 11:30:46 joloef Exp $

% save dummy p
bnbsolvertime = clock;
showprogress('Branch and bound started',p.options.showprogress);
n_in = length(p.c);
% *************************************************************************
% INITIALIZE DIAGNOSTICS ETC
% *************************************************************************
switch max(min(p.options.verbose,3),0)
case 0
    p.options.bmibnb.verbose = 0;
case 1
    p.options.bmibnb.verbose = 1;
    p.options.verbose = 0;
case 2
    p.options.bmibnb.verbose = 2;
    p.options.verbose = 0;
case 3
    p.options.bmibnb.verbose = 2;
    p.options.verbose = 1;
otherwise
    p.options.bmibnb.verbose = 0;
    p.options.verbose = 0;
end

% *************************************************************************
% Assume feasible (this property can be changed in the presolve codes
% *************************************************************************
p.feasible = 1;

% *************************************************************************
% Extract bounds from model
% *************************************************************************
if ~isempty(p.F_struc)
    [p.lb,p.ub,used_rows] = findulb(p.F_struc,p.K);
end

% *************************************************************************
% For quadratic nonconvex programming over linear constraints, we
% diagonalize the problem to obtain less number of bilinear terms
% *************************************************************************
p = quaddiagonalize(p);

% % *************************************************************************
% % Extract bounds from model
% % *************************************************************************
% if ~isempty(p.F_struc)
%     [p.lb,p.ub,used_rows] = findulb(p.F_struc,p.K);
% end

% These two are needed for ex14_1_7
p = fixbounds(p);
p = presolve_bounds_from_equalities(p);
p = preprocess_eval_bounds(p);
p = fixbounds(p);

% *************************************************************************
% The bilinear solver does not support higher order polynomial (i.e. >2). 
% Hence, we need to bilinearize the problem. however, the upper bound
% solver might support polynomial problems, so we should keep a copy of the
% original problem also
% *************************************************************************
[p_bilin,changed] = bilinearize(p);
if (p.solver.uppersolver.constraint.equalities.polynomial &  p.solver.uppersolver.objective.polynomial)
    p_bilin.originalModel = p;
    p = p_bilin;
else
    p = p_bilin;
    p.originalModel = p_bilin;
end

% *************************************************************************
% Pre-calc lists of linear/bilinear/nonlinear variables
% *************************************************************************
[p.linears,p.bilinears,p.nonlinears] = compile_nonlinear_table(p);

% *************************************************************************
% Select branch variables. We should branch on all variables that are
% involved in bilinear terms.
% *************************************************************************
p.branch_variables = decide_branch_variables(p);

% *************************************************************************
% Extract bounds from model
% *************************************************************************
p = preprocess_bilinear_bounds(p);
p = preprocess_eval_bounds(p);

% *************************************************************************
% Now reduce the branch variables by removing bilinear terms that only have
% been introduced due to a convex quadratic objective
% *************************************************************************
p = reduce_bilinear_branching_variables(p);

% *************************************************************************
% Is the given initial solution feasible, or is the zero-solution feasible?
% *************************************************************************
[p,x_min,upper] = initializesolution(p);

% *************************************************************************
% Simple pre-solve loop. The loop is needed for variables defined as w =
% x*y, x = t*u,y=..
% *************************************************************************
i = 0;
goon = 1;
while goon
    start = [p.lb;p.ub];
    i = i+1;
    p = updatenonlinearbounds(p);
    p = presolve_bounds_from_equalities(p);
    p = updatenonlinearbounds(p);   
    p = updatenonlinearbounds(p);    
    p = preprocess_eval_bounds(p);
    i = i+1;
    goon = (norm(start-[p.lb;p.ub],'inf') > 1e-1) & i < 50;
    start = [p.lb;p.ub];
end

% *************************************************************************
% Default root bound improvement
% *************************************************************************
%p.lb = (p.lb+1e5)-1e5;
%p.ub = (p.ub+1e5)-1e5;
close = find(abs(p.lb - p.ub) < 1e-12);
p.lb(close) = (p.lb(close)+p.ub(close))/2;
p.ub(close) = p.lb(close);
p = root_node_tighten(p,upper);
p = updatenonlinearbounds(p);
p = preprocess_eval_bounds(p);
p = presolve_bounds_from_equalities(p);
p = updatenonlinearbounds(p);

output = yalmip_default_output;
if p.feasible
    
    % *******************************
    % Bounded domain?
    % *******************************
    if ~isempty(p.bilinears)
        involved = unique(p.bilinears(:,2:3));
        if any(isinf(p.lb(involved))) | any(isinf(p.ub(involved)))
            output = yalmip_default_output;
            output.Primal  = x_min;                             
            output.problem = -6;
            output.infostr = yalmiperror(-6);
            output.solved_nodes = 0;           
            return
        end
    end
    
    % *******************************
    % Save time & memory
    % *******************************
    p.options.savesolverinput  = 0;
    p.options.savesolveroutput = 0;
    p.options.saveduals = 0;
    p.options.dimacs = 0;    
    
    % *******************************
    % RUN BILINEAR BRANCH & BOUND
    % *******************************
    [x_min,solved_nodes,lower,upper] = branch_and_bound(p,x_min,upper);
    
    % ********************************
    % CREATE SOLUTION AND DIAGNOSTICS
    % ********************************
    problem = 0;
    if isinf(upper)
        problem = 1;
    end
    if isinf(lower) & (lower<0)
        problem = 2;
    end
    if isinf(lower) & (lower>0)
        problem = 1;
    end    
    if solved_nodes == p.options.bnb.maxiter
        problem = 3;
    end
else
    problem = 1;
    x_min = repmat(nan,length(p.c),1);
    solved_nodes = 0;
    lower = inf;
end

x_min = dediagonalize(p,x_min);

output = yalmip_default_output;
output.problem = problem;
output.solved_nodes = solved_nodes;
output.Primal       = x_min(1:n_in);
output.infostr      = yalmiperror(output.problem,'BNB');
output.solvertime   = etime(clock,bnbsolvertime);
output.lower = lower;

function model = fixbounds(model);
polynomials = find(model.variabletype > 0);
LU = max([abs(model.lb) abs(model.ub)],[],2);
for i = 1:length(polynomials)
    j = polynomials(i);
    if j<=length(model.lb)
        vars  = find(model.monomtable(j,:));
        bound = 1;
        for k = 1:length(vars)
            bound = bound * LU(vars(k))^model.monomtable(j,vars(k));
        end
        model.lb(j) = max(model.lb(j),-bound);
        model.ub(j) = min(model.ub(j),bound);
    end
end
even = find(~any(rem(full(model.monomtable),2),2));
model.lb(even) = max(model.lb(even),0);

function pnew = quaddiagonalize(p);
pnew = p;
pnew.V = [];
pnew.diagonalized = 0;

% Any polynomial terms or simple linear by some reason
if any(p.variabletype > 2) & ~all(p.variabletype == 0) | p.options.bmibnb.diagonalize==0
    return
end

if ~isempty(p.evalVariables)
    return
end

if ~isempty(p.binary_variables) | ~isempty(p.integer_variables)
    return
end


nonlinear = find(p.variabletype > 0);
linear = find(p.variabletype == 0);
if ~isempty(p.F_struc)
    % Nonlinear terms in constraints
    if nnz(p.F_struc(:,1 + nonlinear))> 0
        return
    end
end

if ~isempty(p.lb)
    if ~all(isinf(p.lb(nonlinear)))
        return
    end
end
if ~isempty(p.ub)
    if ~all(isinf(p.ub(nonlinear)))
        return
    end
end

% Find quadratic and linear terms
used_in_c = find(p.c);
quadraticterms = used_in_c(find(ismember(used_in_c,nonlinear)));
Q = zeros(length(p.c),length(p.c));
if ~isempty(quadraticterms)
    usedinquadratic = zeros(1,length(p.c));
    for i = 1:length(quadraticterms)
        Qij = p.c(quadraticterms(i));
        power_index = find(p.monomtable(quadraticterms(i),:));
        if length(power_index) == 1
            Q(power_index,power_index) = Qij;
        else
            Q(power_index(1),power_index(2)) = Qij/2;
            Q(power_index(2),power_index(1)) = Qij/2;
        end       
    end
end
Qlin = Q(linear,linear);
clin = p.c(linear);

% Decompose Q
[V,D] = eig(full(Qlin));
V = real(V);
D = real(D);
V(abs(V)<1e-11) = 0;
D(abs(D)<1e-11) = 0;
lb = p.lb(linear);
ub = p.ub(linear);
Z = V';
for i = 1:length(lb)
    z = Z(i,:);
    newub(i,1) = z(z>0)*ub(z>0) + z(z<0)*lb(z<0);
    newlb(i,1) = z(z>0)*lb(z>0) + z(z<0)*ub(z<0);
end


% Create new problem
clin = V'*clin;
%A = A*V;

n = length(linear);
pnew.original_linear = linear;
pnew.original_n = length(p.c);
pnew.V = V;
pnew.c = [clin;diag(D)];
pnew.Q = spalloc(2*n,2*n,0);

% find constraint polytope
if size(p.F_struc,1)>0
    A = -p.F_struc(:,1 + linear);
    b = p.F_struc(:,1);
    pnew.F_struc = [b -A*V zeros(length(b),n)];
end


pnew.variabletype = [zeros(1,n) ones(1,n)*2];
pnew.monomtable = [eye(n);2*eye(n)];
pnew.monomtable(2*n,2*n) = 0;
pnew.lb =-inf(2*n,1);
pnew.ub = inf(2*n,1);
pnew.lb(1:n) = newlb;
pnew.ub(1:n) = newub;
if length(pnew.x0)>0
    pnew.x0 = V*p.x0(1:2);
end
pnew.diagonalized = 1;

function x = dediagonalize(p,x);
if isempty(p.V)
    return
end
y = p.V*x(1:length(x)/2);
x = zeros(p.original_n,1);
x(p.original_linear) = y;






⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -