function [dualUpper,L,U] = derivedualBounds(H,c,A,b,E,f,ops,parametricDomain) if isempty(A) dualUpper = []; L = []; U = []; return end n = length(c); m = length(b); me = length(f); x = sdpvar(n,1); Lambda = sdpvar(m,1); mu = sdpvar(me,1); F = []; if ~isempty(b) F = [F, A*x <= b]; end if ~isempty(f) F = [F, E*x == f]; end % Start by computing primal lower bounds if nargin < 7 ops = sdpsettings('verbose',0); end ops2 = ops; ops2.verbose = max(0,ops.verbose-1);; all_bounded = 1; if ops.verbose disp(['*Computing ' num2str(length(x)) ' primal bounds (required for dual bounds)']); end z = recover(unique([depends(c) depends(b)])); xz = [x;z]; nz = length(z); nTOT = n + length(z); rhs = 0; if ~isempty(b) rhs = rhs + A'*Lambda; end if ~isempty(f) rhs = rhs + E'*mu; end [dummy,L,U] = boundingbox([F,parametricDomain,H*x + c + rhs==0,Lambda>=0],ops2,xz); c0C = full(getbase(c)); c0 = c0C(:,1); C = c0C(:,2:end); if nnz(C)==0 C = spalloc(n,length(z),0); else if length(z)>0 & size(C,2) < length(z) C = []; for i = 1:length(z) C = [C getbasematrix(c,getvariables(z(i)))]; end end end b0B = full(getbase(b)); b0 = b0B(:,1); B = b0B(:,2:end); if nnz(B)==0 B = spalloc(n,length(z),0); else if length(z)>0 & size(B,2) < length(z) B = []; for i = 1:length(z) B = [B getbasematrix(b,getvariables(z(i)))]; end end end if isa(b,'sdpvar') if ops.verbose disp(['*Computing ' num2str(length(b)) ' bounds on parameterized RHS (required for dual bounds)']); end [dummy,bmin,bmax] = boundingbox([F,parametricDomain],ops2,b); end % Lift Hlift = [H C/2;C'/2 zeros(size(C,2))]; if ops.kkt.dualpresolve.lplift XZ = sdpvar(nTOT); end constraints = [Lambda >= 0,parametricDomain,F]; constraints = [constraints,H*x + c + rhs==0]; finiteL = find(~isinf(L)); if ~isempty(finiteL) constraints = [constraints,L(finiteL)<=xz(finiteL)]; end finiteU = find(~isinf(U)); if ~isempty(finiteU) constraints = [constraints,xz(finiteU) <= U(finiteU)]; end if ~isa(f,'double') disp('Parameterized RHS in equality not yet supported in lifting based bounds') ops.kkt.dualpresolve.lplift = 0; end if ops.kkt.dualpresolve.lplift if isempty(f) temp = 0; else temp = f'*mu; end if nnz(Hlift)>0 for i = 1:nTOT for j = i:nTOT if (L(i)==U(i) & L(j)==U(j)) & ~isinf(L(j)) XZ(i,j) = L(i)*L(j); XZ(j,i) = L(i)*L(j); XZ(i,i) = L(i)^2; XZ(j,j) = L(j)^2; elseif L(i)==U(i) & ~isinf(L(i)) XZ(i,j) = L(i)*xz(j); XZ(j,i) = L(i)*xz(j); XZ(i,i) = L(i)^2; elseif L(j)==U(j) & ~isinf(L(j)) XZ(i,j) = L(j)*xz(i); XZ(j,i) = L(j)*xz(i); XZ(j,j) = L(j)^2; else % (xi-Li)(xj-Lj)>0 if ~isinf(L(i)) & ~isinf(L(j)) constraints = [constraints, XZ(i,j)-L(i)*xz(j)-L(j)*xz(i)+L(i)*L(j)>=0]; end % (xi-Li)(Uj-xj)>0 if ~isinf(L(i)) & ~isinf(U(j)) constraints = [constraints, xz(i)*U(j)+L(i)*xz(j)-L(i)*U(j)-XZ(i,j)>=0]; end % (xj-Lj)(Ui-xi)>0 if ~isinf(U(i)) & ~isinf(L(j)) constraints = [constraints, xz(j)*U(i)+L(j)*xz(i)-L(j)*U(i)-XZ(j,i)>=0]; end % (Uj-xj)(Ui-xi)>0 if ~isinf(U(i)) & ~isinf(U(j)) constraints = [constraints, U(j)*U(i)-U(j)*xz(i)-xz(j)*U(i)+XZ(j,i)>=0]; end end end end end if isa(b,'sdpvar') if ~any(isinf(bmax)) constraints = [constraints,-(trace(Hlift*XZ) + c0'*x+temp) <= bmax'*Lambda]; end if ~any(isinf(bmin)) constraints = [constraints,-(trace(Hlift*XZ) + c0'*x+temp) >= bmin'*Lambda]; end else constraints = [constraints,trace(Hlift*XZ) + c0'*x + temp + b'*Lambda==0]; end end if ops.verbose disp(['*Computing ' num2str(length(Lambda)) ' dual bounds']); end ops2.verbose = 0; dualUpper = inf(length(Lambda),1); % always exploit disjoint constraints disjoints = zeros(length(b)); s = sdpvar(length(b),1); % Create an optimizer object which takes no input and returns optimal % Lambda. We will use some hacks to update this model and resolving % with different objectives and constraints. We cannot use multiple % objectives approach since we have different constraints, and we % cannot use optimizer object directly since constraints change p = optimizer([constraints,s == b-A*x],-sum(Lambda),ops2,[],Lambda); Model = p.model; LambdaIndicies = find(Model.c); Model.c = Model.c*0; sIndicies = [ find(Model.used_variables==getvariables(s(1))): find(Model.used_variables==getvariables(s(end)))]; for dualPass = 1:ops.kkt.dualpresolve.passes for i = 1:m if dualUpper(i)>0 iModel = Model; % Maximize Lambda(i)... iModel.c = Model.c*0; iModel.c(LambdaIndicies(i))=-1; % s(i) == 0 iModel.lb(sIndicies(i)) = 0; iModel.ub(sIndicies(i)) = 0; % Add known dual bounds r = find(~isinf(dualUpper)); iModel.ub(LambdaIndicies(r)) = dualUpper(r); % Find disjoint constraints a = A(i,:); a = setdiff(findrows(A,-a),i); iModel.ub(LambdaIndicies(a)) = 0; % Solve this instance p = updatemodel(p,iModel); [Lambda,isol] = p{[]}; sol.problem = isol; if sol.problem == 12 iModel.c = iModel.c*0; p = updatemodel(p,iModel); [Lambda,isol] = p{[]}; sol.problem = isol; if sol.problem == 1 dualUpper(i,1) = 0; elseif sol.problem == 0 sol.problem = 2; end end if sol.problem == 0 dualUpper(i,1) = double(Lambda(i)); elseif sol.problem == 2 dualUpper(i,1) = inf; end end end end if ops.verbose if all(isinf(dualUpper)) disp('*Warning: All dual upper bounds are infinite'); elseif any(isinf(dualUpper)) disp('*Warning: Some of the dual upper bounds are infinite'); else disp('*Success: All dual upper bounds are finite'); end end