function [model,keptvariablesIndex] = eliminatevariables(model,removedparameters,value,parameters) if isempty(removedparameters) keptvariablesIndex = 1:length(model.c); return end keptvariablesIndex = 1:length(model.c); rmvmonoms = model.rmvmonoms; newmonomtable = model.newmonomtable; % Assign evaluation-based values if length(model.evalParameters > 0) alls = [removedparameters(:)' model.evalParameters(:)']; removedP = []; removedE = []; for j = 1:length(removedparameters) for i = 1:length(model.evalMap) if isequal(model.evalMap{i}.variableIndex,removedparameters(j)) p = value(j); index = find(model.evalMap{i}.computes == alls); value(index) = feval(model.evalMap{i}.fcn,p); removedP = [removedP model.evalMap{i}.computes]; removedE = [removedE i]; end end end model.evalVariables(removedE)=[]; model.evalMap = {model.evalMap{setdiff(1:length(model.evalMap),removedE)}}; model.evalParameters = setdiff(model.evalParameters,removedP); end % Evaluate fixed monomial terms aux = model.precalc.aux; if ~isempty(model.precalc.jj1) z = value(model.precalc.jj1).^rmvmonoms(model.precalc.index1); aux(model.precalc.index1) = z; end % Assign simple linear terms if ~isempty(model.precalc.jj2) aux(model.precalc.index2) = value(model.precalc.jj2); end monomvalue = prod(aux,2); removethese = model.removethese; keepingthese = model.keepingthese; % Look for constraints which evaluate to inf + a'*x + b >= 0 infinite_monoms = removethese(isinf(monomvalue(removethese))); if ~isempty(infinite_monoms) if model.K.l > 0 A = model.F_struc(model.K.f + 1:model.K.f + model.K.l,1 + infinite_monoms); redundant = find(all(A,2)); model.F_struc(model.K.f + redundant,:)=[]; model.K.l = model.K.l - length(redundant); end % If that infinite variable is used nowhere else, simply zero it so we % don't get any inf*0 expressions as these leads to nan if ~any(model.F_struc(:,1+infinite_monoms)) monomvalue(infinite_monoms)=0; end end value = monomvalue(removethese); monomgain = monomvalue(keepingthese); if ~isempty(model.F_struc) model.F_struc(:,1) = model.F_struc(:,1)+model.F_struc(:,1+removethese)*value; model.F_struc(:,1+removethese) = []; model.F_struc = model.F_struc*diag(sparse([1;monomgain])); end infeasible = 0; if model.K.f > 0 candidates = find(~any(model.F_struc(1:model.K.f,2:end),2)); %candidates = find(sum(abs(model.F_struc(1:model.K.f,2:end)),2) == 0); if ~isempty(candidates) % infeasibles = find(model.F_struc(candidates,1)~=0); if find(model.F_struc(candidates,1)~=0,1)%;~isempty(infeasibles) model.infeasible = 1; return else model.F_struc(candidates,:) = []; model.K.f = model.K.f - length(candidates); end end end if model.K.l > 0 % Find infeasible constraints candidates = find(~any(model.F_struc(model.K.f + (1:model.K.l),2:end),2)); if ~isempty(candidates) if any(model.F_struc(model.K.f + candidates,1)<-1e-14) model.infeasible = 1; return else model.F_struc(model.K.f + candidates,:) = []; model.K.l = model.K.l - length(candidates); end end % Find constraints f(x) <= inf and remove these candidates = find(isinf(model.F_struc(model.K.f + (1:model.K.l),1)) & (model.F_struc(model.K.f + (1:model.K.l),1))>0); if ~isempty(candidates) model.F_struc(model.K.f + candidates,:) = []; model.K.l = model.K.l - length(candidates); end end if model.K.q(1) > 0 removeqs = []; removeRows = []; top = model.K.f + model.K.l + 1; F_struc = model.F_struc(top:top+sum(model.K.q)-1,:); top = 1; if all(any(F_struc(:,2:end),2)) % There is still something on every row in all SOCPs, we don't have % to search for silly SOCPS ||0|| <= constant else for i = 1:length(model.K.q) rows = top:top+model.K.q(i)-1; v = F_struc(rows,:); if nnz(v(:,2:end))==0 if norm(v(2:end,1)) > v(1,1) model.infeasible = 1; return else removeqs = [removeqs;i]; removeRows = [removeRows;model.K.f+model.K.l+rows]; end end top = top + model.K.q(i); end model.K.q(removeqs)=[]; model.F_struc(removeRows,:)=[]; if isempty(model.K.q) model.K.q = 0; end end end if model.K.s(1) > 0 % Nonlinear semidefinite program with parameter top = model.K.f + model.K.l + sum(model.K.q) + 1; removeqs = []; removeRows = []; for i = 1:length(model.K.s) n = model.K.s(i); rows = top:top+n^2-1; v = model.F_struc(rows,:); if nnz(v)==0 removeqs = [removeqs;i]; removeRows = [removeRows;rows]; elseif nnz(v(:,2:end))==0 Q = reshape(v(:,1),n,n); used = find(any(Q));Qred=Q(:,used);Qred = Qred(used,:); [~,p] = chol(Qred); if p model.infeasible = 1; return else removeqs = [removeqs;i]; removeRows = [removeRows;rows]; end end top = top + n^2; end model.K.s(removeqs)=[]; model.F_struc(removeRows,:)=[]; if isempty(model.K.s) model.K.s = 0; end end model.f = model.f + model.c(removethese)'*value; model.c(removethese)=[]; if nnz(model.Q)>0 model.c = model.c + 2*model.Q(keepingthese,removethese)*value; model.f = model.f + value'*model.Q(removethese,removethese)*value; end if nnz(model.Q)==0 model.Q = spalloc(length(model.c),length(model.c),0); else model.Q(removethese,:) = []; model.Q(:,removethese) = []; end model.c = model.c.*monomgain; keptvariablesIndex(removethese) = []; model.lb(removethese)=[]; model.ub(removethese)=[]; newmonomtable(:,removethese) = []; newmonomtable(removethese,:) = []; if ~isequal(newmonomtable,model.precalc.newmonomtable)%~isempty(removethese) skipped = []; alreadyAdded = zeros(1,size(newmonomtable,1)); [ii,jj,kk,skipped] = stableunique(newmonomtable*model.hashCache(1:size(newmonomtable,2))); %[ii,jj,kk,skipped] = stableunique(newmonomtable*gen_rand_hash(0,size(newmonomtable,2),1)); S = sparse(kk,1:length(kk),1); model.precalc.S = S; model.precalc.skipped = skipped; model.precalc.newmonomtable = newmonomtable; model.precalc.blkOneS = blkdiag(1,S'); else S = model.precalc.S; skipped = model.precalc.skipped; end model.c = S*model.c; if ~isempty(model.F_struc) model.F_struc = model.F_struc*model.precalc.blkOneS; end model.lb(skipped) = []; model.ub(skipped) = []; newmonomtable(skipped,:) = []; newmonomtable(:,skipped) = []; if nnz(model.Q)==0 model.Q = spalloc(length(model.c),length(model.c),0); else model.Q(:,skipped)=[]; model.Q(skipped,:)=[]; end keptvariablesIndex(skipped) = []; model.monomtable = newmonomtable; model = compressModel(model); x0wasempty = isempty(model.x0); model.x0 = zeros(length(model.c),1); % Try to reduce to QP [model,keptvariablesIndex,newmonomtable] = setupQuadratics(model,keptvariablesIndex,newmonomtable); if nnz(model.Q) > 0 if model.solver.objective.quadratic.convex == 0 & model.solver.objective.quadratic.nonconvex == 0 error('The objective instantiates as a quadratic after fixing parameters, but this is not directly supported by the solver. YALMIP will not reformulate models if they structurally change in call to optimizer. A typical trick to circumvent this is to define a new set of variable e, use the quadratic function e''e, and add an equality constraint e = something. The SOCP formulation can then be done a-priori by YALMIP.'); end end if x0wasempty model.x0 = []; end % Remap indicies if ~isempty(model.integer_variables) temp=ismember(keptvariablesIndex,model.integer_variables); model.integer_variables = find(temp); end if ~isempty(model.binary_variables) temp=ismember(keptvariablesIndex,model.binary_variables); model.binary_variables = find(temp); end if ~isempty(model.semicont_variables) temp=ismember(keptvariablesIndex,model.semicont_variables); model.semicont_variables = find(temp); end if ~isempty(model.aux_variables) temp=ismember(keptvariablesIndex,model.aux_variables); model.aux_variables = find(temp); end if ~isempty(model.K.sos) if ~isempty(model.K.sos.variables) for i = 1:length(model.K.sos.variables) temp=ismember(keptvariablesIndex,model.K.sos.variables{i}); model.K.sos.variables{i} = find(temp); end end end model.used_variables = model.used_variables(keptvariablesIndex); % Check if there are remaining strange terms. This occurs in #152 % FIXME: Use code above recursively instead... if ~model.solver.objective.sigmonial & any(model.variabletype == 4) % Bugger. There are signomial terms left, despite elimination, and the % solver does not handle this. YALMIP has introduced an intermediate % variable which is a nasty function of the parameter. signomials = find(model.variabletype == 4); involved = []; for i = 1:length(signomials) m = model.monomtable(signomials(i),:); involved = [involved;find(m ~= fix(m) | m < 0)]; end involved = unique(involved); [lb,ub] = findulb(model.F_struc,model.K,model.lb,model.ub); if all(lb(involved) == ub(involved)) % Now add equality constraints to enforce for i = signomials m = model.monomtable(i,:); involved = find(m ~= fix(m) | m < 0); gain = lb(involved).^m(involved); s = zeros(1,size(model.F_struc,2)); multiplies = setdiff(find(m),involved); s(i+1) = 1; s(multiplies+1) = -gain; model.F_struc = [s;model.F_struc]; model.K.f = model.K.f + 1; end else error('Did not manage to instatiate model. Complicating terms remaining'); end end function model = compressModel(model) model.variabletype = zeros(size(model.monomtable,1),1)'; nonlinear = sum(model.monomtable,2)~=1 | sum(model.monomtable~=0,2)~=1; if ~isempty(nonlinear) model.variabletype(nonlinear) = 3; quadratic = sum(model.monomtable,2)==2; model.variabletype(quadratic) = 2; bilinear = max(model.monomtable,[],2)<=1; model.variabletype(bilinear & quadratic) = 1; sigmonial = any(0>model.monomtable,2) | any(model.monomtable-fix(model.monomtable),2); model.variabletype(sigmonial) = 4; end function [model,keptvariables,newmonomtable] = setupQuadratics(model,keptvariables,newmonomtable); if any(model.variabletype) & all(model.variabletype <= 2) monomials = find(model.variabletype); if nnz(model.F_struc(:,1+monomials))==0 if all(isinf(model.lb(monomials))) if all(isinf(model.ub(monomials))) % OK, the quadratic/bilinear terms only enter in objective, % so let us try to construct Q if isempty(model.precalc.Qmap) ii = []; jj = []; kk = []; for k = monomials(:)' i = find(model.monomtable(k,:)); if model.variabletype(k)==1 model.Q(i(1),i(2)) = model.Q(i(1),i(2)) + model.c(k)/2; model.Q(i(2),i(1)) = model.Q(i(1),i(2)); ii = [ii;i(1)]; jj = [jj;i(2)]; kk = [kk;k]; else model.Q(i,i) = model.Q(i,i) + model.c(k); ii = [ii;i]; jj = [jj;i]; kk = [kk;k]; end end model.precalc.Qmap.M = sparse(sub2ind(size(model.Q),ii,jj),kk,1,prod(size(model.Q)),length(model.c)); model.precalc.Qmap.monomials = monomials; model.precalc.Qmap.monomtable = model.monomtable; else m = model.precalc.Qmap.M*sparse(model.c); m = reshape(m,sqrt(length(m)),[]); model.Q = (m+m')/2; end model.c(monomials)=[]; model.F_struc(:,1+monomials) = []; model.lb(monomials) = []; model.ub(monomials) = []; newmonomtable(monomials,:) = []; newmonomtable(:,monomials) = []; model.monomtable = newmonomtable; model.Q(:,monomials) = []; model.Q(monomials,:) = []; model.x0(monomials) = []; model.variabletype(monomials)=[]; keptvariables(monomials) = []; end end end end