|
1 | 1 | function [x,y,z,info] = cdcs(At,b,c,K,userOpts,initVars)
|
2 |
| - |
3 | 2 | % CDCS
|
4 | 3 | %
|
5 | 4 | % Syntax:
|
6 | 5 | %
|
7 |
| -% [x,y,z,info] = CDCS(At,b,c,K,opts) |
| 6 | +% [x,y,z,info] = CDCS(At,b,c,K,options) |
8 | 7 | %
|
9 |
| -% Solve a sparse conic program using chordal decomposition for the semidefinite |
| 8 | +% Solve a sparse conic program using chordal decomposition for the positive semidefinite |
10 | 9 | % cones and ADMM. CDCS solves the primal (P) or dual (D) standard forms of
|
11 | 10 | % the conic problem,
|
12 | 11 | %
|
13 | 12 | % min <c,x> max <b,y>
|
14 |
| -% (P) s.t. Ax = b, (D) s.t. c - A^Ty = z |
| 13 | +% (P) s.t. Ax = b, (D) s.t. A^Ty + z = c |
15 | 14 | % x \in K z \in K*
|
16 | 15 | %
|
17 |
| -% where A,b and c are the problem date and K is the cone (K* is the dual cone). |
| 16 | +% where A,b and c are the problem data and K is the cone (K* is the dual cone). |
| 17 | +% CDCS supports the following cones: Free, Linear, second-order, |
| 18 | +% Semi-definite, called as called K.f, K.l, K.q, and K.s. |
| 19 | +% |
18 | 20 | % The standard form to be solved is specified by the "solver" field of the
|
19 | 21 | % options structure:
|
20 | 22 | %
|
21 |
| -% opts.solver = 'primal' (default): solve the problem in primal standard form |
22 |
| -% opts.solver = 'dual' : solve the problem in dual standard form |
| 23 | +% options.solver = 'hsde' (default): solve the problem in homogeneous self-dual embedding form |
| 24 | +% options.solver = 'primal' : solve the problem in primal standard form |
| 25 | +% options.solver = 'dual' : solve the problem in dual standard form |
23 | 26 | %
|
24 | 27 | % The chordal decomposition can be carried out in two ways, specified by the
|
25 | 28 | % "chordalize" option:
|
26 | 29 | %
|
27 |
| -% opts.chordalize = 1 (default): split the data equally between the cliques |
28 |
| -% opts.chordalize = 2 : assign data to one clique only |
| 30 | +% options.chordalize = 1 (default): split the data equally between the cliques |
| 31 | +% options.chordalize = 2 : assign data to one clique only |
29 | 32 | %
|
30 | 33 | % <a href="matlab:help('cdcsOpts')">Click here for a complete list of options</a>.
|
31 | 34 | %
|
32 | 35 | % The output structure 'info' contains the following information:
|
33 | 36 | %
|
34 | 37 | % info.problem: - 0: CDCS terminated succesfully
|
35 |
| -% - 1: the maximum number of iterations was reached |
36 |
| -% - 2: the ADMM iterations terminated succesfully, but the positive |
37 |
| -% matrix completion algorithm threw an error |
| 38 | +% - 1: primal infeasibility detected |
| 39 | +% - 2: dual infeasibility detected |
| 40 | +% - 3: maximum number of iterations reached |
| 41 | +% - 4: the ADMM iterations terminated succesfully, but the positive |
| 42 | +% matrix completion algorithm threw an error |
38 | 43 | % info.iter: number of iterations
|
39 | 44 | % info.cost: terminal cost
|
40 | 45 | % info.pres: terminal primal ADMM residual
|
41 | 46 | % info.dres: terminal dual ADMM residual
|
| 47 | +% info.log : history log of the ADMM residuals, cost, etc. |
42 | 48 | % info.time: some timing information (setup, ADMM iterations, cleanup, total)
|
43 | 49 | %
|
44 | 50 | % See also CDCSOPTS
|
|
61 | 67 |
|
62 | 68 |
|
63 | 69 | %============================================
|
64 |
| -% Solver options |
| 70 | +% Solver options & import cdcs_utils |
65 | 71 | %============================================
|
66 | 72 | tstart = tic;
|
67 | 73 | opts = cdcsOpts;
|
| 74 | +import cdcs_utils.* |
68 | 75 |
|
69 | 76 |
|
70 | 77 | %============================================
|
|
76 | 83 | end
|
77 | 84 |
|
78 | 85 | % Checks on specified solver type and method
|
79 |
| -if ~any(strcmpi(opts.solver,{'primal','dual'})) |
80 |
| - error('Unknown opts.solver. Please use "primal" or "dual".') |
| 86 | +if ~any(strcmpi(opts.solver,{'primal','dual','hsde'})) |
| 87 | + error('Unknown opts.solver. Please use "primal", "dual" or "hsde".') |
81 | 88 | end
|
82 | 89 |
|
83 | 90 | % Print nice welcoming header
|
84 | 91 | if opts.verbose
|
85 |
| - myline1 = [repmat('=',1,64),'\n']; |
| 92 | + [header,myline1,myline2] = printHeader(opts); |
86 | 93 | fprintf(myline1)
|
87 | 94 | fprintf('CDCS by G. Fantuzzi, Y. Zheng -- v1.0\n')
|
88 | 95 | fprintf(myline1)
|
|
93 | 100 | % start timing
|
94 | 101 | proctime = tic;
|
95 | 102 |
|
96 |
| -% sparsify everything, check cone constraints, rescale |
| 103 | +% sparsify everything, check cone constraints |
97 | 104 | [At,b,c,K,opts] = checkInputs(At,b,c,K,opts);
|
98 |
| -[At,b,c,K,opts] = rescaleData(At,b,c,K,opts); |
99 | 105 | [At,b,c,K,opts] = splitBlocks(At,b,c,K,opts);
|
100 | 106 | [opts.n,opts.m] = size(At);
|
101 | 107 |
|
102 |
| -% chordal decomposition |
| 108 | +% rescale & chordal decomposition |
103 | 109 | Kold = K;
|
104 |
| -[At,b,c,K,Ech,cd,chstuff] = chordalize(At,b,c,K,opts); |
| 110 | +[At,b,c,K,Ech,chstuff,opts] = preprocess(At,b,c,K,opts); |
105 | 111 |
|
106 | 112 | % basic decomposed problem dimensions: no. of cones, no. of vectorized conic
|
107 | 113 | % variables, and no. of free primal variables
|
|
114 | 120 | [X,Y,Z,others] = makeVariables(K,initVars,opts);
|
115 | 121 |
|
116 | 122 | % Make operators for ADMM
|
117 |
| -[step1,step2,step3,checkConv] = makeADMM(At,b,c,K,cd,Ech,opts); |
| 123 | +[updateX,updateY,updateZ,checkConvergence] = makeADMM(At,b,c,K,Ech,opts); |
118 | 124 |
|
119 | 125 | % Time setup and display
|
120 | 126 | proctime = toc(proctime);
|
121 | 127 | if opts.verbose
|
122 |
| - myline2 = [repmat('-',1,64),'\n']; |
| 128 | + % Set method to display |
| 129 | + if strcmpi(opts.solver,'hsde') |
| 130 | + method = 'homogeneous self-dual embedding'; |
| 131 | + else |
| 132 | + method = opts.solver; |
| 133 | + end |
123 | 134 | fprintf('done in %.4f seconds. \n',proctime);
|
124 |
| - fprintf('Standard form : %s\n',opts.solver); |
| 135 | + fprintf('Algorithm : %s\n',method); |
125 | 136 | fprintf('Chordalization method : %i\n',opts.chordalize);
|
126 | 137 | fprintf('Adaptive penalty : %i\n',opts.adaptive);
|
127 | 138 | fprintf('Scale data : %i\n',opts.rescale);
|
128 | 139 | fprintf('Free variables : %i \n',K.f);
|
129 | 140 | fprintf('Non-negative variables : %i \n',K.l);
|
130 |
| - fprintf('Second-order cones : %i (max. size: %i)\n',length(K.q),max(K.q)); |
131 |
| - fprintf('Semidefinite cones : %i (max. size: %i)\n',length(K.s),max(K.s)); |
| 141 | + fprintf('Second-order cones : %i (max. size: %i)\n',length(find(K.q ~=0)),max(K.q)); |
| 142 | + fprintf('Semidefinite cones : %i (max. size: %i)\n',length(find(K.s ~=0)),max(K.s)); |
132 | 143 | fprintf('Affine constraints : %i \n',opts.m);
|
133 | 144 | fprintf('Consensus constraints : %i \n',sum(accumarray(Ech,1)));
|
134 |
| - fprintf(myline1) |
| 145 | + fprintf(myline1); |
| 146 | + fprintf(header); |
| 147 | + fprintf(myline2); |
135 | 148 | end
|
136 | 149 |
|
137 | 150 | %============================================
|
138 | 151 | % Run ADMM
|
139 | 152 | %============================================
|
140 |
| -% Display |
141 |
| -if opts.verbose |
142 |
| - fprintf(' iter | pres | dres | cost | rho | time (s) |\n') |
143 |
| - fprintf(myline2) |
144 |
| -end |
145 |
| - |
146 | 153 | admmtime = tic;
|
147 |
| -opts.feasCode = 1; |
148 | 154 | for iter = 1:opts.maxIter
|
149 | 155 |
|
150 | 156 | % Save current iterate for convergence test
|
151 | 157 | YOld = Y;
|
152 | 158 |
|
153 | 159 | % Update block variables
|
154 |
| - [X,others] = step1(X,Y,Z,opts.rho,others); |
155 |
| - [Y,others] = step2(X,Y,Z,opts.rho,others); |
156 |
| - [Z,others] = step3(X,Y,Z,opts.rho,others); |
| 160 | + [X,others] = updateX(X,Y,Z,opts.rho,others); |
| 161 | + [Y,others] = updateY(X,Y,Z,opts.rho,others); |
| 162 | + [Z,others] = updateZ(X,Y,Z,opts.rho,others); |
157 | 163 |
|
158 | 164 | % log errors / check for convergence
|
159 |
| - [isConverged,log,opts] = checkConv(X,Y,Z,YOld,others,iter,admmtime,opts); |
160 |
| - if isConverged |
161 |
| - opts.feasCode = 0; |
| 165 | + [stop,info,log,opts] = checkConvergence(X,Y,Z,YOld,others,iter,admmtime,opts); |
| 166 | + if stop |
162 | 167 | break;
|
163 | 168 | end
|
164 | 169 | end
|
165 | 170 | admmtime = toc(admmtime);
|
166 |
| -if opts.verbose |
167 |
| - fprintf(myline1) |
168 |
| -end |
169 | 171 |
|
170 | 172 | %============================================
|
171 | 173 | % Outputs
|
172 | 174 | %============================================
|
173 | 175 | % Variables in sedumi format
|
174 | 176 | posttime = tic;
|
175 |
| -[x,y,z,opts] = setOutputs(X,Y,Z,others,Kold,cd,Ech,chstuff,opts); |
| 177 | +[x,y,z,info,opts] = setOutputs(X,Y,Z,others,Kold,c,Ech,chstuff,info,opts); |
176 | 178 | posttime = toc(posttime);
|
177 | 179 |
|
178 | 180 | % Info
|
179 |
| -info.problem = opts.feasCode; % diagnostic code |
180 | 181 | info.iter = iter; % # of iterations
|
181 |
| -info.cost = log.cost; % terminal cost |
182 |
| -info.pres = log.pres; % terminal primal ADMM res |
183 |
| -info.dres = log.dres; % terminal dual ADMM res |
| 182 | +info.cost = log(iter).cost; % terminal cost |
| 183 | +info.pres = log(iter).pres; % terminal primal ADMM res |
| 184 | +info.dres = log(iter).dres; % terminal dual ADMM res |
| 185 | +info.log = log; % log of residuals etc |
184 | 186 | info.time.setup = proctime; % setup time
|
185 | 187 | info.time.admm = admmtime; % ADMM time
|
186 | 188 | info.time.cleanup = posttime; % post-processing time
|
187 | 189 | info.time.total = toc(tstart); % total CPU time
|
188 | 190 |
|
189 | 191 | % Print summary
|
190 | 192 | if opts.verbose
|
| 193 | + fprintf(myline1) |
191 | 194 | fprintf(' SOLUTION SUMMARY:\n')
|
192 | 195 | fprintf('------------------\n')
|
193 | 196 | fprintf(' Termination code : %11.1d\n',info.problem)
|
|
0 commit comments