0001 function out = bbnnls(A, b, x0, opt)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035 fgx = @(x) funcGrad(A,b, x);
0036
0037
0038 out.iter = 0;
0039 out.iterTimes = nan*ones(opt.maxit,1);
0040 out.objTimes = nan*ones(opt.maxit,1);
0041 out.pgTimes = nan*ones(opt.maxit,1);
0042 out.trueError = nan*ones(opt.maxit,1);
0043 out.startTime = tic;
0044 out.status = 'Failure';
0045
0046
0047 out.x = x0;
0048 out.refx = x0;
0049 [out.refobj, out.grad] = fgx(out.x);
0050 out.oldg = out.grad;
0051 out.refg = out.oldg;
0052
0053
0054
0055 if (opt.verbose)
0056 fprintf('Running: **** SBB-NNLS ****\n\n');
0057 fprintf('Iter \t Obj\t\t ||pg||_inf\t\t ||x-x*||\n');
0058 fprintf('-------------------------------------------------------\n');
0059 end
0060
0061 objectives = zeros(opt.maxit,1);
0062
0063 while 1
0064 out.iter = out.iter + 1;
0065
0066
0067 [termReason, out.pgTimes(out.iter)] = checkTermination(opt, out);
0068 if (termReason > 0), break; end
0069
0070
0071 [step out] = computeBBStep(A, b, out);
0072 out.x = out.x - step * out.grad;
0073 out.oldg = out.grad;
0074
0075
0076
0077 out.x(out.x < 0) = 0;
0078
0079 [out.obj out.grad] = fgx(out.x);
0080
0081 objectives(out.iter) = out.obj;
0082
0083
0084
0085
0086
0087
0088
0089
0090 out.objTimes (out.iter) = out.obj;
0091 out.iterTimes(out.iter) = toc(out.startTime);
0092
0093
0094 if (opt.truex), out.trueError(out.iter) = norm(opt.xt-out.x); end
0095 if (opt.verbose)
0096 fprintf('%04d\t %E\t%E\t%E\n', out.iter, out.obj, out.pgTimes(out.iter), out.trueError(out.iter));
0097 end
0098 end
0099
0100
0101 out.time = toc(out.startTime);
0102 out.status = 'Success';
0103 out.termReason = setTermReason(termReason);
0104 end
0105
0106
0107
0108 function [step out] = computeBBStep(A, b, out)
0109
0110
0111 gp = find(out.x == 0 & out.grad > 0);
0112 out.oldg(gp) = 0;
0113
0114 Ag = A*out.oldg;
0115
0116
0117 if (mod(out.iter, 2) == 0)
0118 step = (out.oldg' * out.oldg) / (Ag' * Ag);
0119 else
0120 numer = Ag' * Ag;
0121 Ag = A'*Ag;
0122 Ag(gp) = 0;
0123 step = numer / (Ag' * Ag);
0124 end
0125 end
0126
0127
0128
0129 function [f g] = funcGrad(A, b, x)
0130 Ax = A*x - b;
0131 f = 0.5*norm(Ax)^2;
0132 if (nargout > 1)
0133 g = A'*Ax;
0134 end
0135 end
0136
0137
0138
0139
0140
0141 function [v pg] = checkTermination(options, out)
0142
0143 gp = find( (out.x ~= 0 | out.grad < 0));
0144
0145 pg = norm(out.grad(gp), 'inf');
0146 if (pg < options.tolg), v=8; return; end
0147
0148
0149 if (options.time_limit)
0150 out.time = etime(clock, out.start_time);
0151 if (out.time >= options.maxtime)
0152 v = 1;
0153 return;
0154 end
0155 end
0156
0157
0158 if (options.use_tolx)
0159 if (norm(out.x-out.oldx)/norm(out.oldx) < options.tolx)
0160 v = 2;
0161 return;
0162 end
0163 end
0164
0165
0166 if (options.use_tolo && out.iter > 2)
0167 delta = abs(out.objTimes(out.iter-1)-out.objTimes(out.iter-2));
0168 if (delta < options.tolo)
0169 v = 3;
0170 return;
0171 end
0172 end
0173
0174
0175 if (out.iter >= options.maxit)
0176 v = 4;
0177 return;
0178 end
0179
0180
0181 if (options.use_kkt)
0182 if abs(out.x' * out.grad) <= options.tolk
0183 v = 7;
0184 return;
0185 end
0186 end
0187
0188
0189
0190 v = 0;
0191 end
0192
0193
0194 function showStatus(out, options)
0195 if (options.verbose)
0196 fprintf('.');
0197 if (mod(out.iter, 30) == 0)
0198 fprintf('\n');
0199 end
0200 end
0201 end
0202
0203
0204 function r = setTermReason(t)
0205 switch t
0206 case 1
0207 r = 'Exceeded time limit';
0208 case 2
0209 r = 'Relative change in x small enough';
0210 case 3
0211 r = 'Relative change in objvalue small enough';
0212 case 4
0213 r = 'Maximum number of iterations reached';
0214 case 5
0215 r = '|x_t+1 - x_t|=0 or |grad_t+1 - grad_t| < 1e-9';
0216 case 6
0217 r = 'Line search failed';
0218 case 7
0219 r = '|x^T * grad| < opt.pbb_gradient_norm';
0220 case 8
0221 r = '|| grad ||_inf < opt.tolg';
0222 case 100
0223 r = 'The active set converged';
0224 otherwise
0225 r = 'Undefined';
0226 end
0227 end
0228