source: proiecte/pmake3d/make3d_original/Make3dSingleImageStanford_version0.1/third_party/opt/yalmip/extras/compileinterfacedata.m @ 37

Last change on this file since 37 was 37, checked in by (none), 14 years ago

Added original make3d

File size: 36.0 KB
Line 
1function [interfacedata,recoverdata,solver,diagnostic,F,Fremoved] = compileinterfacedata(F,aux_obsolete,P,h,options,findallsolvers,parametric)
2
3persistent CACHED_SOLVERS
4persistent EXISTTIME
5persistent NCHECKS
6
7diagnostic = [];
8interfacedata = [];
9recoverdata = [];
10solver = [];
11Fremoved  = [];
12
13if nargin<7
14    parametric = 0;
15end
16
17if isequal(h,0)
18    h = [];
19end
20
21% *************************************************************************
22% EXTRACT LOW-RANK DESCRIPTION
23% *************************************************************************
24lowrankdetails = getlrdata(F);
25if ~isempty(lowrankdetails)
26    F = F(~is(F,'lowrank'));
27end
28
29% *************************************************************************
30% PERTURB STRICT INEQULAITIES
31% *************************************************************************
32if isa(options.shift,'sdpvar') | (options.shift~=0)
33    F = shift(F,options.shift);
34end
35
36% *************************************************************************
37% ADD RADIUS CONSTRAINT
38% *************************************************************************
39if isa(options.radius,'sdpvar') | ~isinf(options.radius)
40    x = recover(unique(union(depends(h),depends(F))));
41    if length(x)>1
42        F = F + set(cone(x,options.radius));
43    else
44        F = F + set(-options.radius < x < options.radius);
45    end
46end
47
48% *************************************************************************
49% CONVERT LOGIC CONSTRAINTS
50% *************************************************************************
51[F,changed] = convertlogics(F);
52if changed
53    options.saveduals = 0; % Don't calculate duals since we changed the problem
54end
55
56% *************************************************************************
57% Take care of the nonlinear operators by converting expressions such as
58% t = max(x,y) to standard conic models and mixed integer models
59% This part also adds parts from logical expressions and mpower terms
60% *************************************************************************
61if options.expand
62    % Experimental hack due to support for the PWQ function used for
63    % quadratic dynamic programming with MPT.
64    % FIX: Clean up and generalize
65    try
66        variables = uniquestripped([depends(h) getvariables(h)]);
67        extendedvariables = yalmip('extvariables');
68        index_in_extended = find(ismembc(variables,extendedvariables));
69        if ~isempty(index_in_extended)
70            extstruct = yalmip('extstruct',variables(index_in_extended));
71            if isequal(extstruct.fcn ,'pwq_yalmip')
72                [Fz,properties,arguments]=model(extstruct.var,'milp',options,extstruct);
73                gain = getbasematrix(h,getvariables(extstruct.var));
74                h = replace(h,extstruct.var,0);
75                h = h + gain*properties.replacer;
76                F = F + Fz;
77            end
78        end
79    catch
80    end
81    [F,failure,cause] = expandmodel(F,h,options);
82    if failure % Convexity propgation failed
83        interfacedata = [];
84        recoverdata = [];
85        solver = '';
86        diagnostic.solvertime = 0;
87        diagnostic.problem = 14;
88        diagnostic.info = yalmiperror(14,cause);
89        return
90    end
91    evalVariables = yalmip('evalVariables');
92    if isempty(evalVariables)
93        evaluation_based = 0;
94    else
95        evaluation_based = ~isempty(intersect([getvariables(h) getvariables(F)],evalVariables));
96    end
97else
98    evaluation_based = 0;   
99end
100
101% *************************************************************************
102% CONVERT CONVEX QUADRATIC CONSTRAINTS
103% We do not convert quadratic constraints to SOCPs if we have have
104% sigmonial terms (thus indicating a GP problem), if we have relaxed
105% nonlinear expressions, or if we have specified a nonlinear solver.
106% Why do we convert them already here? Don't remember, should be cleaned up
107% *************************************************************************
108[monomtable,variabletype] = yalmip('monomtable');
109% if any(variabletype(getvariables(F))==4)
110%     do_not_convert = 1;
111% else
112%     do_not_convert = 0;
113% end
114do_not_convert = any(variabletype(getvariables(F))==4);
115do_not_convert = do_not_convert | strcmpi(options.solver,'pennlp') | strcmpi(options.solver,'penbmi');
116do_not_convert = do_not_convert | strcmpi(options.solver,'fmincon') | strcmpi(options.solver,'lindo');
117do_not_convert = do_not_convert | strcmpi(options.solver,'fmincon-geometric') | strcmpi(options.solver,'fmincon-standard');
118do_not_convert = do_not_convert | strcmpi(options.solver,'bmibnb');
119do_not_convert = do_not_convert | (options.convertconvexquad == 0);
120do_not_convert = do_not_convert | (options.relax == 1);
121if ~do_not_convert
122    [F,socp_changed] = convertquadratics(F);
123    if socp_changed % changed holds the number of QC -> SOCC conversions
124        options.saveduals = 0; % We cannot calculate duals since we changed the problem
125    end
126else
127    socp_changed = 0;
128end
129
130% CHEAT FOR QC
131if socp_changed>0 & length(find(is(F,'socc')))==socp_changed
132    socp_are_really_qc = 1;
133else
134    socp_are_really_qc = 0;
135end
136
137% *************************************************************************
138% LOOK FOR AVAILABLE SOLVERS
139% Finding solvers can be very slow on some systems. To alleviate this
140% problem, YALMIP can cache the list of avaialble solvers.
141% *************************************************************************
142if (options.cachesolvers==0) | isempty(CACHED_SOLVERS)
143    getsolvertime = clock;
144    solvers = getavailablesolvers(findallsolvers,options);
145    getsolvertime = etime(clock,getsolvertime);
146    % CODE TO INFORM USERS ABOUT SLOW NETWORKS!
147    if isempty(EXISTTIME)
148        EXISTTIME = getsolvertime;
149        NCHECKS = 1;
150    else
151        EXISTTIME = [EXISTTIME getsolvertime];
152        NCHECKS = NCHECKS + 1;
153    end
154    if (options.cachesolvers==0)
155        if ((NCHECKS >= 3 & (sum(EXISTTIME)/NCHECKS > 1)) | EXISTTIME(end)>2)
156            if warningon
157                info = 'Warning: YALMIP has detected that your drive or network is unusually slow.\nThis causes a severe delay in SOLVESDP when I try to find available solvers.\nTo avoid this, use the options CACHESOLVERS in SDPSETTINGS.\nSee the FAQ for more information.\n';
158                fprintf(info);
159            end
160        end
161    end
162    if length(EXISTTIME) > 5
163        EXISTTIME = EXISTTIME(end-4:end);
164        NCHECKS = 5;
165    end
166    CACHED_SOLVERS = solvers;
167else
168    solvers = CACHED_SOLVERS;
169end
170
171% *************************************************************************
172% NO SOLVER AVAILABLE
173% *************************************************************************
174if isempty(solvers)
175    diagnostic.solvertime = 0;
176    if isempty(options.solver)
177        diagnostic.info = yalmiperror(-2,'YALMIP');
178        diagnostic.problem = -2;
179    else
180        diagnostic.info = yalmiperror(-3,'YALMIP');
181        diagnostic.problem = -3;
182    end
183    if warningon & options.warning & isempty(findstr(diagnostic.info,'No problems detected'))
184        disp(['Warning: ' diagnostic.info]);
185    end
186    return
187end
188
189% *************************************************************************
190% WHAT KIND OF PROBLEM DO WE HAVE NOW?
191% *************************************************************************
192[ProblemClass,integer_variables,binary_variables,parametric_variables,uncertain_variables,quad_info] = categorizeproblem(F,P,h,options.relax,parametric,evaluation_based);
193
194% *************************************************************************
195% SELECT SUITABLE SOLVER
196% *************************************************************************
197[solver,problem] = selectsolver(options,ProblemClass,solvers,socp_are_really_qc);
198
199if isempty(solver)
200    diagnostic.solvertime = 0;
201    if problem == -4
202        diagnostic.info = yalmiperror(problem,options.solver);
203    else
204        diagnostic.info = yalmiperror(problem,'YALMIP');
205    end
206    diagnostic.problem = problem;
207
208    if warningon & options.warning
209        disp(['Warning: ' diagnostic.info]);
210    end
211    return
212end
213if length(solver.version)>0
214    solver.tag = [solver.tag '-' solver.version];
215end
216
217% *************************************************************************
218% DID WE SELECT THE INTERNAL BNB SOLVER
219% IN THAT CASE, SELECT LOCAL SOLVER
220% (UNLESS ALREADY SPECIFIED IN OPTIONS.BNB)
221% *************************************************************************
222localsolver.qc = 0;
223localsolver = solver;
224if strcmpi(solver.tag,'bnb')
225    temp_options = options;
226    temp_options.solver = options.bnb.solver;
227    tempProblemClass = ProblemClass;
228    tempProblemClass.constraint.binary  = 0;
229    tempProblemClass.constraint.integer = 0;
230    localsolver = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
231    if isempty(localsolver) | strcmpi(localsolver.tag,'bnb')
232        diagnostic.solvertime = 0;
233        diagnostic.info = yalmiperror(-2,'YALMIP');
234        diagnostic.problem = -2;
235        return
236    end
237    solver.lower = localsolver;
238end
239
240% *************************************************************************
241% DID WE SELECT THE INTERNAL EXPERIMENTAL KKT SOLVER
242% IN THAT CASE, SELECT SOLVER TO SOLVE THE MILP PROBLEM
243% *************************************************************************
244localsolver.qc = 0;
245localsolver = solver;
246if strcmpi(solver.tag,'kktqp')
247    temp_options = options;
248    temp_options.solver = '';
249    tempProblemClass = ProblemClass;
250    tempProblemClass.constraint.binary = 1;
251    tempProblemClass.objective.quadratic.convex = 0;
252    tempProblemClass.objective.quadratic.nonconvex = 0;
253    localsolver = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
254    if isempty(localsolver) | strcmpi(localsolver.tag,'bnb') | strcmpi(localsolver.tag,'kktqp')
255        diagnostic.solvertime = 0;
256        diagnostic.info = yalmiperror(-2,'YALMIP');
257        diagnostic.problem = -2;
258        return
259    end
260    solver.lower = localsolver;
261end
262
263% *************************************************************************
264% DID WE SELECT THE LMIRANK?
265% FIND SDP SOLVER FOR INITIAL SOLUTION
266% *************************************************************************
267if strcmpi(solver.tag,'lmirank')
268    temp_options = options;
269    temp_options.solver = options.lmirank.solver;
270    tempProblemClass = ProblemClass;
271    tempProblemClass.constraint.inequalities.rank = 0;
272    tempProblemClass.constraint.inequalities.semidefinite.linear = 1;
273    tempProblemClass.objective.linear = 1;
274    initialsolver = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
275    if isempty(initialsolver) | strcmpi(initialsolver.tag,'lmirank')
276        diagnostic.solvertime = 0;
277        diagnostic.info = yalmiperror(-2,'YALMIP');
278        diagnostic.problem = -2;
279        return
280    end
281    solver.initialsolver = initialsolver;
282end
283
284% *************************************************************************
285% DID WE SELECT THE INTERNAL BMIBNB SOLVER? SELECT UPPER/LOWER SOLVERs
286% (UNLESS ALREADY SPECIFIED IN OPTIONS)
287% *************************************************************************
288if strcmpi(solver.tag,'bmibnb')
289
290    % Relax problem for lower solver
291    tempProblemClass = ProblemClass;
292
293    sdp = tempProblemClass.constraint.inequalities.semidefinite;
294    tempProblemClass.constraint.inequalities.semidefinite.linear = sdp.linear | sdp.quadratic | sdp.polynomial;
295    tempProblemClass.constraint.inequalities.semidefinite.quadratic = 0;
296    tempProblemClass.constraint.inequalities.semidefinite.polynomial = 0;
297
298    lp = tempProblemClass.constraint.inequalities.elementwise;
299    tempProblemClass.constraint.inequalities.elementwise.linear = lp.linear | lp.quadratic.convex | lp.quadratic.nonconvex | sdp.polynomial;
300    tempProblemClass.constraint.inequalities.elementwise.quadratic.convex = 0;
301    tempProblemClass.constraint.inequalities.elementwise.quadratic.nonconvex = 0;
302    tempProblemClass.constraint.inequalities.elementwise.polynomial = 0;
303
304    equ = tempProblemClass.constraint.equalities;
305    tempProblemClass.constraint.equalities.linear = equ.linear | equ.quadratic | equ.polynomial;
306    tempProblemClass.constraint.equalities.quadratic = 0;
307    tempProblemClass.constraint.equalities.polynomial = 0;
308
309    %     if nnz(quad_info.Q) > 0
310    %     if all(eig(quad_info.Q) > -1e-12)
311    %     tempProblemClass.objective.quadratic.convex = 0;
312    %     tempProblemClass.objective.quadratic.nonconvex = 0;
313    %     else
314    %    tempProblemClass.objective.quadratic.convex = 0;
315    tempProblemClass.objective.quadratic.nonconvex = 0;
316    tempProblemClass.objective.polynomial = 0;
317    %    end
318    %    end
319
320    tempProblemClass.constraint.inequalities.rank  = 0;
321    tempProblemClass.evaluation  = 0;
322
323    temp_options = options;
324    temp_options.solver = options.bmibnb.lowersolver;
325
326    % If the problem actually is quadratic, try to get a convex problem
327    % this will typically allow us to solver better lower bounding problems
328    % (we don't have to linearize the cost)
329    [lowersolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
330    if isempty(lowersolver)| strcmpi(lowersolver.tag,'bmibnb') | strcmpi(lowersolver.tag,'bnb')
331        % No, probably non-convex cost. Pick a linear solver instead and go
332        % for lower bound based on a complete "linearization"
333        tempProblemClass.objective.quadratic.convex = 0;
334        [lowersolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
335    end
336
337    if isempty(lowersolver)| strcmpi(lowersolver.tag,'bmibnb') | strcmpi(lowersolver.tag,'bnb')
338        tempbinary = tempProblemClass.constraint.binary;
339        tempinteger = tempProblemClass.constraint.integer;
340        tempProblemClass.constraint.binary = 0;
341        tempProblemClass.constraint.integer = 0;
342        [lowersolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
343        tempProblemClass.constraint.binary = tempbinary;
344        tempProblemClass.constraint.integer = tempinteger;
345    end
346
347    if isempty(lowersolver) | strcmpi(lowersolver.tag,'bmibnb') | strcmpi(lowersolver.tag,'bnb')
348        diagnostic.solvertime = 0;
349        diagnostic.info = yalmiperror(-2,'YALMIP');
350        diagnostic.problem = -2;
351        return
352    end
353    solver.lowercall = lowersolver.call;
354    solver.lowersolver = lowersolver;
355
356    temp_options = options;
357    temp_options.solver = options.bmibnb.uppersolver;
358    temp_ProblemClass = ProblemClass;
359    temp_ProblemClass.constraint.binary = 0;
360    temp_ProblemClass.constraint.integer = 0;
361    temp_ProblemClass.objective.quadratic.convex = 0;
362    temp_ProblemClass.objective.quadratic.nonconvex = 0;
363    [uppersolver,problem] = selectsolver(temp_options,temp_ProblemClass,solvers,socp_are_really_qc);
364    if strcmpi(uppersolver.tag,'bnb')
365        temp_options.solver = 'none';
366        [uppersolver,problem] = selectsolver(temp_options,temp_ProblemClass,solvers,socp_are_really_qc);
367    end
368    if isempty(uppersolver) | strcmpi(uppersolver.tag,'bmibnb')
369        diagnostic.solvertime = 0;
370        diagnostic.info = yalmiperror(-2,'YALMIP');
371        diagnostic.problem = -2;
372        return
373    end
374    solver.uppercall = uppersolver.call;
375    solver.uppersolver = uppersolver;
376
377
378    temp_options = options;
379    temp_options.solver = options.bmibnb.lpsolver;
380    tempProblemClass.constraint.inequalities.semidefinite.linear = 0;
381    tempProblemClass.constraint.inequalities.semidefinite.quadratic = 0;
382    tempProblemClass.constraint.inequalities.semidefinite.polynomial = 0;
383    tempProblemClass.constraint.inequalities.secondordercone = 0;
384    tempProblemClass.objective.quadratic.convex = 0;
385    tempProblemClass.objective.quadratic.nonconvex = 0;
386    tempProblemClass.objective.quadratic.nonconvex = 0;
387    tempProblemClass.objective.polynomial = 0;
388
389    [lpsolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
390
391    if isempty(lowersolver)| strcmpi(lowersolver.tag,'bmibnb')
392        tempbinary = tempProblemClass.constraint.binary;
393        tempProblemClass.constraint.binary = 0;
394        [lpsolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
395        tempProblemClass.constraint.binary = tempbinary;
396    end
397
398    if isempty(lpsolver) | strcmpi(lpsolver.tag,'bmibnb')
399        diagnostic.solvertime = 0;
400        diagnostic.info = yalmiperror(-2,'YALMIP');
401        diagnostic.problem = -2;
402        return
403    end
404    solver.lpsolver = lpsolver;
405    solver.lpcall = lpsolver.call;
406end
407
408% *************************************************************************
409% DID WE SELECT THE INTERNAL SDPMILP SOLVER
410% This solver solves MISDP problems by solving MILP problems and adding SDP
411% cuts based on the infasible MILP solution.
412% *************************************************************************
413if strcmpi(solver.tag,'cutsdp')
414
415    % Relax problem for lower solver
416    tempProblemClass = ProblemClass;
417    tempProblemClass.constraint.inequalities.elementwise.linear =  tempProblemClass.constraint.inequalities.elementwise.linear |     tempProblemClass.constraint.inequalities.semidefinite.linear | tempProblemClass.constraint.inequalities.secondordercone;
418    tempProblemClass.constraint.inequalities.semidefinite.linear = 0;
419    tempProblemClass.constraint.inequalities.secondordercone = 0;
420
421    temp_options = options;
422    temp_options.solver = options.cutsdp.solver;
423
424    [cutsolver,problem] = selectsolver(temp_options,tempProblemClass,solvers,socp_are_really_qc);
425
426    if isempty(cutsolver) | strcmpi(cutsolver.tag,'cutsdp') |strcmpi(cutsolver.tag,'bmibnb') | strcmpi(cutsolver.tag,'bnb')
427        diagnostic.solvertime = 0;
428        diagnostic.info = yalmiperror(-2,'YALMIP');
429        diagnostic.problem = -2;
430        return
431    end
432    solver.cutsolver = cutsolver;
433end
434
435showprogress(['Solver chosen : ' solver.tag],options.showprogress);
436
437% *************************************************************************
438% CONVERT MAXDET TO SDP USING GEOMEAN?
439% *************************************************************************
440% MAXDET using geometric mean construction
441if ~isempty(P) & solver.objective.maxdet==0
442    t = sdpvar(1,1);
443    if isequal(P,sdpvar(F(end)))
444        F = F(1:end-1);
445    end
446    F = F + detset(t,P);
447    if isempty(h)
448        h = -t;
449    else
450        h = h-t;
451        % Warn about logdet -> det^1/m
452        if options.verbose>0 & options.warning>0
453            disp(' ')
454            disp('Objective c''x-logdet(P) has been changed to c''x-det(P)^(1/(2^ceil(log2(length(X))))).')
455            disp('See the MAXDET section in the manual for details.')
456            disp(' ')
457        end
458    end
459end
460
461% *************************************************************************
462% Change binary variables to integer?
463% *************************************************************************
464old_binary_variables = binary_variables;
465if ~isempty(binary_variables) & (solver.constraint.binary==0)
466    x_bin = recover(binary_variables(ismember(binary_variables,unique([getvariables(h) getvariables(F)]))));
467    F = F + set(x_bin<1)+set(x_bin>0);
468    integer_variables = union(binary_variables,integer_variables);
469    binary_variables = [];
470end
471
472% *************************************************************************
473% Model quadratics using SOCP?
474% Should not be done when using PENNLP or BMIBNB, or if we have relaxed the
475% monmial terms or...Ouch, need to clean up all special cases, this sucks.
476% *************************************************************************
477convertQuadraticObjective = ~strcmpi(solver.tag,'pennlp-standard');
478convertQuadraticObjective = convertQuadraticObjective & ~strcmpi(solver.tag,'bmibnb');
479convertQuadraticObjective = convertQuadraticObjective & ( ~(options.relax==1 | options.relax==3)  &(~isempty(quad_info) & solver.objective.quadratic.convex==0 | (~isempty(quad_info) & strcmp(solver.tag,'bnb') & localsolver.objective.quadratic.convex==0)));
480if strcmpi(solver.tag,'bnb') & ~isempty(quad_info)
481    if solver.lower.objective.quadratic.convex==0
482        convertQuadraticObjective = 1;
483    end
484end
485if convertQuadraticObjective
486    t = sdpvar(1,1);
487    x = quad_info.x;
488    R = quad_info.R;
489    if ~isempty(R)
490        c = quad_info.c;
491        f = quad_info.f;
492        F = F + lmi(cone([2*R*x;1-(t-c'*x-f)],1+t-c'*x-f));
493        h = t;
494    end
495    quad_info = [];
496end
497if solver.constraint.inequalities.rotatedsecondordercone == 0
498    [F,changed] = convertlorentz(F);
499    if changed
500        options.saveduals = 0; % We cannot calculate duals since we change the problem
501    end
502end
503% Whoa, horrible tests to find out when to convert SOCP to SDP
504% This should not be done if :
505%   1. Problem is actually a QCQP and solver supports this
506%   2. Problem is integer, local solver supports SOCC
507%   3. Solver supports SOCC
508if ~((solver.constraint.inequalities.elementwise.quadratic.convex == 1) & socp_are_really_qc)
509    if ~(strcmp(solver.tag,'bnb') & socp_are_really_qc & localsolver.constraint.inequalities.elementwise.quadratic.convex==1 )
510        if ((solver.constraint.inequalities.secondordercone == 0) | (strcmpi(solver.tag,'bnb') & localsolver.constraint.inequalities.secondordercone==0))
511            [F,changed] = convertsocp(F);
512            if changed
513                options.saveduals = 0; % We cannot calculate duals since we change the problem
514            end
515        end
516    end
517end
518
519% *************************************************************************
520% Add logaritmic barrier cost/constraint for MAXDET and SDPT3-4. Note we
521% have to add it her ein order for a complex valued matrix to be converted.
522% *************************************************************************
523if ~isempty(P) & solver.objective.maxdet==1
524    F = F + set(P > 0);
525end
526
527if ((solver.complex==0) & ProblemClass.complex) | ((strcmp(solver.tag,'bnb') & localsolver.complex==0) & ProblemClass.complex)
528    showprogress('Converting to real constraints',options.showprogress)
529    F = imag2reallmi(F);
530    options.saveduals = 0; % We cannot calculate duals since we change the problem
531end
532
533% *************************************************************************
534% CREATE OBJECTIVE FUNCTION c'*x+x'*Q*x
535% *************************************************************************
536showprogress('Processing objective h(x)',options.showprogress);
537try
538    if strcmpi(solver.tag,'bmibnb') | strcmpi(solver.tag,'pennlp-standard')
539        tempoptions = options;
540        tempoptions.relax = 1;
541        [c,Q,f]=createobjective(h,P,tempoptions,quad_info);
542    else
543        [c,Q,f]=createobjective(h,P,options,quad_info);
544    end
545catch
546    error(lasterr)
547end
548
549% *************************************************************************
550% Convert {F(x),G(x)} to a numerical SeDuMi-like format
551% *************************************************************************
552showprogress('Processing F(x)',options.showprogress);
553[F_struc,K,KCut] = lmi2sedumistruct(F);
554% We add a field to remember the dimmesion of the logarithmic cost.
555% Actually, the actually value is not interesting, we know that the
556% logarithmic cost corresponds to the last SDP constraint anyway
557K.m = length(P);
558
559% *************************************************************************
560% SOME HORRIBLE CODE TO DETERMINE USED VARIABLES
561% *************************************************************************
562% Which sdpvar variables are actually in the problem
563used_variables_LMI = find(any(F_struc(:,2:end),1));
564used_variables_obj = find(any(c',1) | any(Q));
565used_variables = uniquestripped([used_variables_LMI used_variables_obj]);
566% The problem is that linear terms might be missing in problems with only
567% nonlinear expressions
568[monomtable,variabletype] = yalmip('monomtable');
569if (options.relax==1)|(options.relax==3)
570    monomtable = [];
571    nonlinearvariables = [];
572    linearvariables = used_variables;
573else
574    nonlinearvariables = find(variabletype);
575    linearvariables = used_variables(find(variabletype(used_variables)==0));
576end
577needednonlinear = nonlinearvariables(ismembc(nonlinearvariables,used_variables));
578linearinnonlinear = find(sum(abs(monomtable(needednonlinear,:)),1));
579missinglinear = setdiff(linearinnonlinear(:),linearvariables);
580used_variables = uniquestripped([used_variables(:);missinglinear(:)]);
581
582% *************************************************************************
583% So are we done now? No... What about variables hiding inside so called
584% evaluation variables. We detect these, and at the same time set up the
585% structures needed to support general functions such as exp, log, etc
586% NOTE : This is experimental code
587% FIX  : Clean up...
588% *************************************************************************
589[evalMap,evalVariables,used_variables,nonlinearvariables,linearvariables] = detectHiddenNonlinear(used_variables,options,nonlinearvariables,linearvariables);
590
591% *************************************************************************
592% REMOVE UNNECESSARY VARIABLES FROM PROBLEM
593% *************************************************************************
594if length(used_variables)<yalmip('nvars')
595    c = c(used_variables);
596    Q = Q(:,used_variables);Q = Q(used_variables,:);
597    if ~isempty(F_struc)
598        F_struc = sparse(F_struc(:,[1 1+used_variables]));
599    end
600end
601
602% *************************************************************************
603% Map variables and constraints in low-rank definition to local stuff
604% *************************************************************************
605if ~isempty(lowrankdetails)
606    % Identifiers of the SDP constraints
607    lmiid = getlmiid(F);
608    for i = 1:length(lowrankdetails)
609        lowrankdetails{i}.id = find(ismember(lmiid,lowrankdetails{i}.id));
610        if ~isempty(lowrankdetails{i}.variables)
611            index = ismember(used_variables,lowrankdetails{i}.variables);
612            lowrankdetails{i}.variables = find(index);
613        end
614    end
615end
616
617% *************************************************************************
618% SPECIAL VARIABLES
619% Relax = 1 : relax both integers and nonlinear stuff
620% Relax = 2 : relax integers
621% Relax = 3 : relax nonlinear stuff
622% *************************************************************************
623if (options.relax==1) | (options.relax==3)
624    nonlins = [];
625end
626if (options.relax) | (options.relax==2)
627    integer_variables = [];
628    binary_variables  = [];
629    old_binary_variables  = find(ismember(used_variables,old_binary_variables));
630else
631    integer_variables = find(ismember(used_variables,integer_variables));
632    binary_variables  = find(ismember(used_variables,binary_variables));
633    old_binary_variables  = find(ismember(used_variables,old_binary_variables));
634end
635parametric_variables  = find(ismember(used_variables,parametric_variables));
636extended_variables =  find(ismember(used_variables,yalmip('extvariables')));
637
638
639% *************************************************************************
640% Equality constraints not supported or supposed to be removed
641% *************************************************************************
642% We may save some data in order to reconstruct
643% dual variables related to equality constraints that
644% have been removed.
645oldF_struc = [];
646oldQ = [];
647oldc = [];
648oldK = K;
649Fremoved = [];
650if (K.f>0)
651    % reduce if user explicitely says remove, or user says nothing but
652    % solverdefinitions does, and there are no nonlinear variables
653    if ((options.removeequalities==1 | options.removeequalities==2) & isempty(intersect(used_variables,nonlinearvariables))) | ((options.removeequalities==0) & (solver.constraint.equalities.linear==-1))
654        showprogress('Solving equalities',options.showprogress);
655        [x_equ,H,A_equ,b_equ,factors] = solveequalities(F_struc,K,options.removeequalities==1);
656        % Exit if no consistent solution exist
657        if (norm(A_equ*x_equ-b_equ,'inf')>1e-5)%sqrt(eps)*size(A_equ,2))
658            diagnostic.solvertime = 0;
659            diagnostic.info = yalmiperror(1,'YALMIP');
660            diagnostic.problem = 1;
661            solution = diagnostic;
662            solution.variables = used_variables(:);
663            solution.optvar = x_equ;
664            % And we are done! Save the result
665            % sdpvar('setSolution',solution);
666            return
667        end
668        % We dont need the rows for equalities anymore
669        oldF_struc = F_struc;
670        oldc = c;
671        oldQ = Q;
672        oldK = K;
673        F_struc = F_struc(K.f+1:end,:);
674        K.f = 0;
675        Fold = F;
676        [nlmi neq]=size(F);
677        F = lmi;
678        Fremoved = set([]);
679        for i = 1:nlmi+neq
680            if ~is(Fold(i),'equality')
681                F = F + Fold(i);
682            else
683                Fremoved = Fremoved + Fold(i);
684            end
685        end
686
687        % No variables left. Problem solved!
688        if size(H,2)==0
689            diagnostic.solvertime = 0;
690            diagnostic.info = yalmiperror(0,'YALMIP');
691            diagnostic.problem = 0;
692            solution = diagnostic;
693            solution.variables = used_variables(:);
694            solution.optvar = x_equ;
695            % And we are done! Save the result
696            % Note, no dual is saved
697            sdpvar('setSolution',solution);
698            p = checkset(F);
699            if any(p<1e-5)
700                diagnostic.info = yalmiperror(1,'YALMIP');
701                diagnostic.problem = 1;
702            end
703            return
704        end
705        showprogress('Converting problem to new basis',options.showprogress)
706
707        % objective in new basis
708        f = f + x_equ'*Q*x_equ;
709        c = H'*c + 2*H'*Q*x_equ;
710        Q = H'*Q*H;Q=((Q+Q')/2);
711        % LMI in new basis
712        F_struc = [F_struc*[1;x_equ] F_struc(:,2:end)*H];
713    else
714        % Solver does not support equality constraints and user specifies
715        % double-sided inequalitis to remove them
716        if (solver.constraint.equalities.linear==0 | options.removeequalities==-1)
717            % Add equalities
718            F_struc = [-F_struc(1:1:K.f,:);F_struc];
719            K.l = K.l+K.f*2;
720            % Keep this in mind...
721            K.fold = K.f;
722            K.f = 0;
723        end
724        % For simpliciy we introduce a dummy coordinate change
725        x_equ   = 0;
726        H       = 1;
727        factors = [];
728    end
729else
730    x_equ   = 0;
731    H       = 1;
732    factors = [];
733end
734
735
736% *************************************************************************
737% Setup the initial solution
738% *************************************************************************
739x0 = [];
740if options.usex0
741    if options.relax
742        x0_used = relaxdouble(recover(used_variables));
743    else
744        %FIX : Do directly using yalmip('solution')
745        x0_used = double(recover(used_variables));
746    end
747    x0 = zeros(sdpvar('nvars'),1);
748    x0(used_variables)  = x0_used(:);
749    x0(isnan(x0))=0;
750end
751if ~isempty(x0)
752    % Get a coordinate in the reduced space
753    x0 = H\(x0(used_variables)-x_equ);
754end
755
756% Monomial table for nonlinear variables
757% FIX : Why here!!! mt handled above also
758[mt,variabletype] = yalmip('monomtable');
759if size(mt,1)>size(mt,2)
760    mt(size(mt,1),size(mt,1)) = 0;
761end
762% In local variables
763mt = mt(used_variables,used_variables);
764variabletype = variabletype(used_variables);
765if (options.relax)|(options.relax==3)
766    mt = eye(length(used_variables));
767end
768
769% FIX : Make sure these things work...
770lub = yalmip('getbounds',used_variables);
771lb = lub(:,1)-inf;
772ub = lub(:,2)+inf;
773lb(old_binary_variables) = max(lb(old_binary_variables),0);
774ub(old_binary_variables) = min(ub(old_binary_variables),1);
775
776% This does not work if we have used removeequalities, so we clear them for
777% safety. note that bounds are not guaranteed to be used according to the
778% manual, so this is allowed, although it might be a bit inconsistent to
779% some users.
780if ~isempty(oldc)
781    lb = [];
782    ub = [];
783end
784
785% *************************************************************************
786% GENERAL DATA EXCHANGE WITH SOLVER
787% *************************************************************************
788interfacedata.F_struc = F_struc;
789interfacedata.c = c;
790interfacedata.Q = Q;
791interfacedata.f = f;
792interfacedata.K = K;
793interfacedata.lb = lb;
794interfacedata.ub = ub;
795interfacedata.x0 = x0;
796interfacedata.options = options;
797interfacedata.solver  = solver;
798interfacedata.monomtable = mt;
799interfacedata.variabletype = variabletype;
800interfacedata.integer_variables   = integer_variables;
801interfacedata.binary_variables    = binary_variables;
802interfacedata.uncertain_variables = [];
803interfacedata.parametric_variables= parametric_variables;
804interfacedata.extended_variables  = extended_variables;
805interfacedata.used_variables      = used_variables;
806interfacedata.lowrankdetails = lowrankdetails;
807interfacedata.problemclass = ProblemClass;
808interfacedata.KCut = KCut;
809interfacedata.getsolvertime = 1;
810% Data to be able to recover duals when model is reduced
811interfacedata.oldF_struc = oldF_struc;
812interfacedata.oldc = oldc;
813interfacedata.oldK = oldK;
814interfacedata.factors = factors;
815interfacedata.Fremoved = Fremoved;
816interfacedata.evalMap = evalMap;
817interfacedata.evalVariables = evalVariables;
818
819% *************************************************************************
820% GENERAL DATA EXCANGE TO RECOVER SOLUTION AND UPDATE YALMIP VARIABLES
821% *************************************************************************
822recoverdata.H = H;
823recoverdata.x_equ = x_equ;
824recoverdata.used_variables = used_variables;
825
826function yesno = warningon
827
828s = warning;
829if isa(s,'char')
830    yesno = isequal(s,'on');
831else
832    yesno = isequal(s(1).state,'on');
833end
834
835
836
837
838
839
840
841
842
843
844function [evalMap,evalVariables,used_variables,nonlinearvariables,linearvariables] = detectHiddenNonlinear(used_variables,options,nonlinearvariables,linearvariables)
845
846evalVariables = yalmip('evalVariables');
847old_used_variables = used_variables;
848goon = 1;
849if ~isempty(evalVariables)
850    while goon
851        % Which used_variables are representing general functions
852        evalVariables = yalmip('evalVariables');
853        usedEvalVariables = find(ismember(used_variables,evalVariables));
854        evalMap =  yalmip('extstruct',used_variables(usedEvalVariables));
855        if ~isa(evalMap,'cell')
856            evalMap = {evalMap};
857        end
858        % Find all variables used in the arguments of these functions
859        hidden = [];
860        for i = 1:length(evalMap)
861            if isequal(getbase(evalMap{i}.arg{1}),[0 1])% & is(evalMap{i}.arg{1},'linear')
862                for j = 1:length(evalMap{i}.arg)-1
863                    % The last argument is the help variable z in the
864                    % transformation from f(ax+b) to f(z),z==ax+b. We should not
865                    % use this transformation if the argument already is unitary
866                    hidden = [hidden getvariables(evalMap{i}.arg{j})];
867                end
868            else
869                for j = 1:length(evalMap{i}.arg)
870                    % The last argument is the help variable z in the
871                    % transformation from f(ax+b) to f(z),z==ax+b. We should not
872                    % use this transformation if the argument already is unitary
873                    hidden = [hidden getvariables(evalMap{i}.arg{j})];
874                end
875            end
876        end
877        used_variables = union(used_variables,hidden);
878
879        % The problem is that linear terms might be missing in problems with only
880        % nonlinear expressions
881        [monomtable,variabletype] = yalmip('monomtable');
882        if (options.relax==1)|(options.relax==3)
883            monomtable = [];
884            nonlinearvariables = [];
885            linearvariables = used_variables;
886        else
887            nonlinearvariables = find(variabletype);
888            linearvariables = used_variables(find(variabletype(used_variables)==0));
889        end
890        needednonlinear = nonlinearvariables(ismembc(nonlinearvariables,used_variables));
891        linearinnonlinear = find(sum(abs(monomtable(needednonlinear,:)),1));
892        missinglinear = setdiff(linearinnonlinear(:),linearvariables);
893        used_variables = uniquestripped([used_variables(:);missinglinear(:)]);
894
895
896        usedEvalVariables = find(ismember(used_variables,evalVariables));
897        evalMap =  yalmip('extstruct',used_variables(usedEvalVariables));
898        if ~isa(evalMap,'cell')
899            evalMap = {evalMap};
900        end
901        evalVariables = usedEvalVariables;
902
903        for i = 1:length(evalMap)
904            if isequal(getbase(evalMap{i}.arg{1}),[0 1])
905                index = ismember(used_variables,getvariables(evalMap{i}.arg{1}));
906                evalMap{i}.variableIndex = find(index);
907            else
908                index = ismember(used_variables,getvariables(evalMap{i}.arg{end}));
909                evalMap{i}.variableIndex = find(index);
910            end
911        end
912        goon = ~isequal(used_variables,old_used_variables);
913        old_used_variables = used_variables;
914    end
915else
916    evalMap = [];
917end
918
Note: See TracBrowser for help on using the repository browser.