function varargout = reducedLP(varargin); % reducedLP Solves linear programming problems in standard form. % The algorithm uses primal-dual methods where only the `M' % most nearly active constraints of the dual are taken into % account in the normal equation matrix. % Speedups in the time per iteration are thus expected % for linear programs where the number of (primal) % variables is much larger than the number of constraints. % Preliminary test results show that the number of iterations % to solution hardly increases, sometimes even decreases, for % M as small as 5 or 10 percent of the total number of constraints. % Accordingly, significant speedups in the time to solution % can be expected. % % [X,Y] = reducedLP(A,B,C) returns the primal optimal solution X % and the dual optimal solution Y to the linear programming problem % min C'X subject to AX = B, X >= 0. % % [X,Y,LOGS] = reducedLP(A,B,C) further returns % a structure containing information collected during runtime. % % reducedLP(A,B,C,OPTS) specifies options: % In general, the value 1 means 'active' and 0 means 'inactive'. % OPTS.M: number of constraints to keep [integer | {size(A,2)}] % OPTS.M_rel: M/size(A,2) [scalar | {OPTS.M/size(A,2)}] % OPTS.disp: verbose printing at each outer step [0 | {1} | 2] % OPTS.disp_fig: displays figure [{0} | 1] % OPTS.show_title: shows figure title [0 | {1}] % OPTS.tol: convergence tolerance [scalar | {1e-6}] % OPTS.tol_soft_constr: tolerance for soft constraint heuristic % [scalar | {1e-14}] % OPTS.iter_ubound: maximal number of iterations % [integer | {1e2}] % OPTS.beta: beta parameter [scalar | {.99}] % OPTS.xmax: xmax parameter [scalar | {1e15}] % OPTS.xunder: xunder [scalar | {1e-4}] % OPTS.x0: initial x (primal variables) [{automatically % selected}] % OTPS.y0: initial y (dual variables) [{automatically selected}] % OPTS.method: Primal-Dual Affine Scaling % or Mehrotra Predictor Corrector [PDAS | {MPC}] % OPTS.mu: way the centering parameter is computed [{Wright} | Mehrotra] % OPTS.SFSOP: use Mehrotra's SFSOP routine [{0} | 1] % OPTS.sparse: sparse equation solver [0 | {1}] % OPTS.Chol: [0 for backslash operator | 1 for Choleski (CHOL) % | {2} for CHOLINC(.,'inf')] % OPTS.loading: diagonal loading [scalar | {0}] % OPTS.nb_rep: number of repetitions (in order to stabilize % measured CPU times) [integer | {1}] % OPTS.log_scalar: return LOGS for scalar values [0 | {1}] % OPTS.log_dual: return LOGS for y [{0} | 1] % OPTS.log_primal: return LOGS for x and s [{0} | 1] % % Please report bugs to P.-A. Absil % (http://www.montefiore.ulg.ac.be/~absil/) % based on ipas35.m % This is a copy of ipas35_fn03.m % Copyright P.-A. Absil, 2005. % ipas35_fn03.m - PA - Started Mon 06 Jun 2005, CSIT. % I have to test now. % ipas35_fn02.m - PA - Started Mon 06 Jun 2005, kag1. % Go on. % ipas35_fn01.m - PA - Started Sun 05 Jun 2005, CSIT. % Turn it into a function. % ********************************************************* % ********************************************************* % Process inputs and do error checking % ********************************************************* % ********************************************************* if nargin<3 error('Not enough input arguments.') end A = varargin{1}; b = varargin{2}; c = varargin{3}; if nargin==4 opts = varargin{4}; else opts = []; end [m,n] = size(A); % The variables set below determine the behaviour of the code. % Most of the variable names start with "sw_", which stands for "switch". % Particular attention should be paid to the choices commented with % "!!!". % In general, the value '1' means "yes", "on", and zero means the contrary. % Choice of M (or k here) if isfield(opts,'M') k = opts.M; elseif isfield(opts,'M_rel') k = round(n*opts.M_rel); else k = n; % Default choice end % Display figure: if isfield(opts,'disp_fig') disp_fig = opts.disp_fig; else disp_fig = 0; end % Print info during run if isfield(opts,'disp') sw_verbose = opts.disp else sw_verbose = 0; % !!! has to be checked end % Turn figure title on/off if isfield(opts,'show_title') show_title = opts.show_title; else show_title = 1; end % Convergence tolerance: (default in paper: 1e-8) if isfield(opts,'tol') tol_conv = opts.tol; else tol_conv = 1e-6; end % Tolerance for soft constraints. if isfield(opts,'tol_soft_constr') tol_soft_constr = opts.tol_soft_constr; else tol_soft_constr = 1e-14; % Default: 1e-14 end % Upper bound on number of iterations if isfield(opts,'iter_ubound') iter_ubound = opts.iter_ubound; else iter_ubound = 1e2; % Default: 1e2 end % ** Parameters of the algorithm if isfield(opts,'beta') beta = opts.beta; else beta = .99; end if isfield(opts,'xmax') xmax = opts.xmax; else xmax = 1e15; end if isfield(opts,'xunder') xunder = opts.xunder; else xunder = 1e-4; end % Choice of x0 if isfield(opts,'x0') x0 = opts.x0; x0 = x0(:); end % Choice of y0 if isfield(opts,'y0') y0 = opts.y0; y0 = y0(:); end % Automatic choices of x0 and y0 % -1: x0, y0 given. % 0: x0 = ones(m,1); % 1: x0 min norm solution of Ax=b % 2: x0 as in Mehrotra (SIOPT, 1992), but modified for dual-feasibility. % 3: x0, y0, s0 as in Mehrotra. % Note that in this case y_0 is not always dual feasible % and s_0 is not the exact slack. sw_xy0 = -1; if ~exist('x0') sw_xy0 = 2; if ~exist('y0') sw_xy0 = 3; end end % xxx Test feasibility if IPAS. % Choice of method % 0: Affine scaling (no mu parameter) % 1: Mehrotra predictor-corrector, as described e.g. % in [NW99, Chap 14]. if isfield(opts,'method') if isequal(opts.method,'PDAS') | isequal(opts.method,'pdas') sw_MPC = 0; else sw_MPC = 1; end else sw_MPC = 1; end % Choice of the way the mu parameter is selected: % 0: as in Wright % 1: as in Mehrotra. if isfield(opts,'mu') if opts.mu == 'Wright' sw_mu_Meh = 0; elseif opts.mu == 'Mehrotra' sw_mu_Meh = 1; else error(['OPTS.mu = ', opts.mu ,' not defined']) end else sw_mu_Meh = 0; end % SFSOP is a subroutine defined in [Mehrotra 1992]. % 0: as in Wright (linear) - this is simpler than Mehrotra's SFSOP % 1: as in [Mehrotra 1992] (quadratic expansion of central path) % SFSOP stands for Step From Second-Order Polynomial % % Our experiments suggest that sw_mu_Meh and sw_Meh_SFSOP don't help. if isfield(opts,'SFSOP') if opts.SFSOP == 1 sw_Meh_SFSOP = 1; else sw_Meh_SFSOP = 0; end else sw_Meh_SFSOP = 0; end sw_Meh_GTSF = 0; % Default: 0 (1 not implemented) % 0: "Classical" update. % 1: With GTSF heuristic in [Meh92, p588]. "The step factor in the primal space is % chosen so that the product of primal blocking variable (ls) and the % corresponding dual slack is nearly equal to the value their product % would take at the point on the central trajectory at which the % duality gap is equal to (x-p_x)'(s-p_s)/(n*gamma_a)." % Choose dual update rule if sw_MPC == 0 sw_d_update = 1; else sw_d_update = 0; end % Default: 1 (if sw_MPC=0) / 0 (if sw_MPC=1) !!! % 0: Classical update rule (clipped below by beta tbar). % 1: Update rule involving tbar-||Delta y||, for superlinear convergence. % Choose primal update rule if sw_MPC == 0 sw_p_update = 2; else sw_p_update = 0; end % Default: 2 (if sw_MPC=0) / 0 (if sw_MPC=1) !!! % 0: Classical update rule along Delta x. % 1: First update rule (not along Delta x, without x_-). % 2: Update rule involving x_-. sw_sc_dy = 0; % Default: 0. % Turns norm(dy) into norm(dy./dy0) in update rules. % New, 10 May 2005. sw_sc_Q = 0; % Default: 0. % Selects Q on the basis of (c-A'*y)./abs(c-A'*y0) % New, 10 May 2005. sw_force_decr_xs = 0; % Default: 0 % 1: Scale the updates (new 17 Oct 2004) psi_xs = .75; % must be in (.5,1) % Goal: get global convergence for affine scaling non feasible, % by forcing x's to decrease (the p and d residuals will decrease, % too, by linearity). % Result: does not work well. We hit the constraints x>0, s>0 too % soon, i.e., t primal and t dual are very small. % This is because the Newton step tries to achieve c-A'y-s=0. But if % c-A'y has negative components, then s will try to go negative... % Choose dense/sparse solver % Involved in the computation of the primal-dual matrix. % 0: No sparse (full matrices). % 1: Sparse. if isfield(opts,'sparse') && opts.sparse == 0 sw_sparse = 0; else sw_sparse = 1; end % xxx Use && everywhere. if isfield(opts,'Chol') sw_Chol = opts.Chol; else sw_Chol = 2; end % Default: 1/2 !!! % 0: Solve systems using Matlab's backslash operator. % 1: Solve systems using chol. % 2: Force Cholinc. if isfield(opts,'loading') val_loading = opts.loading; else val_loading = 0; end % !!! Default: 0 (or 1e-8) % Diagonal loading. % Purpose: help the approximate normal matrix be pd sw_Q = 1; % Default: 1 % Select heuristic for the choice of the index set Q. % 0: Q = {1,...,n} % 1: Q = indices of the k smallest entries of s. % 2: Q = (k largest x/s) U (m smallest s). % 3: Q = k largest x/s. % 4: Q = (ind k smallest s) U (ind m lin ind col) sw_soft_constr = 1; % Default: 1 % Soft constraints allow the constraints to slightly recede. % 0: Hard constraints. % 1: Soft constraints: s = max(1e-14,s) sw_xtilde = 0; % Default: 0 % 0: Compute full xtilde. % 1: Compute xtildeQ and put the rest to zero. % First feasibility check d_feasible = 1; % Default: 1 % Assume that the problem is dual-feasible. % Will be modified later if necessary. % This variable has to be eventually set to 0 if y0 is not feasible. if isfield(opts,'y0') && any(c-A'*y0<0) d_feasible = 0; end if ~sw_MPC & ~d_feasible error('PDAS with dual infeasible initial conditions') end % Choose number of repetitions if isfield(opts,'nb_rep') nb_rep = opts.nb_rep; else nb_rep = 1; end % This makes it possible to run problems several times and return the % mean CPU over all runs. % xxx May be changed later? % Determine what the LOG structure should return if nargout >= 3 if isfield(opts,'log_scalar') sw_log_scalar = opts.log_scalar; else sw_log_scalar = 1; end if isfield(opts,'log_dual') sw_log_dual = opts.log_dual; else sw_log_dual = 0; end if isfield(opts,'log_primal') sw_log_primal = opts.log_primal; else sw_log_primal = 0; end else sw_log_scalar = 0; sw_log_dual = 0; sw_log_primal = 0; end % ********************************************************* % ********************************************************* % Various stuff % ********************************************************* % ********************************************************* % ******* If requested, find m lin ind cols of A: %if sw_Q==4 % load woodw_Q_li %end if sw_Q==4 % & 1==0 first_zero = 1; bl_nr = 0; while first_zero == 1 bl_nr = bl_nr+1; [Qt,Rt,Et] = qr(full(A(:,(bl_nr-1)*m+1:bl_nr*m))); ind_zero = find(abs(diag(Rt))<1e-5); first_zero = ind_zero(1) end Rt = Rt(:,1:first_zero-1); Q_li = [1:m]*Et; Q_li = Q_li(1:first_zero-1); Q_li = Q_li + (bl_nr-1)*m; size_Q_li = length(Q_li); j = bl_nr*m; while size_Q_li < m j = j+1; if ~mod(j,100), j end [Qtt,Rtt] = qrinsert(Qt,Rt,size_Q_li+1,full(A(:,j))); width_Rtt = size(Rtt,2); if abs(Rtt(width_Rtt,width_Rtt)) > 1e-5; Qt = Qtt; Rt = Rtt; Q_li = [Q_li,j]; size_Q_li = size_Q_li+1 if rank(full(A(:,Q_li)))==size_Q_li disp('Full rank') else disp('Rank deficient!') pause end end end end % if sw_Q==4 % ******* clear all evol variables (quite tricky!) to_del = char(who('*evol')); for i=1:size(to_del,1) var_to_del = to_del(i,:); j = length(var_to_del); while var_to_del(j)==' ' j=j-1; end var_to_del = var_to_del(1:j); clear(var_to_del) end % ******* clear all _v variables (quite tricky!) to_del = char(who('*_v')); for i=1:size(to_del,1) var_to_del = to_del(i,:); j = length(var_to_del); while var_to_del(j)==' ' j=j-1; end var_to_del = var_to_del(1:j); clear(var_to_del) end if sw_verbose > 0 k end CPU_tic = cputime; CPU_normal_tot = 0; CPU_solve_tot = 0; CPU_step2_tot = 0; CPU_x0_tot = 0; CPU_Q_tot = 0; CPU_stop_tot = 0; iter_tot = 0; % ********************************************************* % ********************************************************* % LOOP ON REPETITIONS % ********************************************************* % ********************************************************* for rep=1:nb_rep % ** Data CPUt_x0=cputime; switch sw_xy0 case 0 x = ones(n,1); case 1 [U,R] = qr(A',0); x = U*(R'\b); x = x + max(0,-1.5*min(x)); x0 = x; case 2 % Mehrotra for x_0 only (not y_0 nor s_0) % [U,R] = qr(A',0); % This is very slow ! % Use this instead: if ~exist('s0') s0 = c-A'*y0; end Af = full(A); [U,R] = qr(Af',0); x = U*(R'\b); xpdx = x + max(0,-1.5*min(x)); x = xpdx + .5*(xpdx'*s0)/sum(s0); case 3 % Mehrotra SIOPT 2(4):575-601, 1992, p589. % Beware! This modifies initial y and s, too. % [U,R] = qr(A',0); % This is very slow ! % Use this instead: Af = full(A); [U,R] = qr(Af',0); y0 = R\(U'*c); s_tilde = c-A'*y0; x_tilde = U*(R'\b); dx = max(0,-1.5*min(x_tilde)); ds = max(0,-1.5*min(s_tilde)); dx_tilde = dx + .5*(x_tilde+dx)'*(s_tilde+ds)/sum(s_tilde+ds); ds_tilde = ds + .5*(x_tilde+dx)'*(s_tilde+ds)/sum(x_tilde+dx); % y = y_0; s = s_tilde + ds_tilde; x = x_tilde + dx_tilde; d_feasible = 0; end y = y0; if d_feasible s = c-A'*y; % Ensure dual feasibility (dual equality satisfied) end CPU_x0_tot = CPU_x0_tot + cputime - CPUt_x0; % ** Prepare storage: %D2AT = zeros(n,m); test_conv = 0; test_div = 0; iter = 0; % *** DISPLAY INFOS if sw_verbose==2 disp('***') iter %err %max(y) disp(['c-A^Ty>=0? ', num2str(all(c-A'*y>=0))]) disp(['c-A^Ty-s=0? ', num2str(all(abs(c-A'*y-s)<=1e-6))]) %that_p %that_d %beta_xs disp(['xTs = ', num2str(x'*s)]) disp(['Primal resid = ', num2str(norm(b-A*x))]) disp(['Dual resid = ', num2str(norm(c-A'*y-s))]) end % ********************************************************* % LOOP ON ITERATES (y,x,s) % ********************************************************* % ************* Loop on iterates (y,x,s) ************* while ~test_conv & ~test_div if d_feasible cmAty = s; % cmAty = c-A'*y else cmAty = c-A'*y; end if sw_sc_Q & iter==0 cmAty0 = cmAty; end CPUtt_tic = cputime; % ** Choose Q: switch sw_Q case 0 Q = [1:n]; case 1 if ~sw_sc_Q [ignore,Qfull] = sort(cmAty); else [ignore,Qfull] = sort(cmAty./abs(cmAty0)); end Q = Qfull(1:k); case 2 % the k largest x/s and the m smallest s [ignore,ind_s_sort] = sort(cmAty); [ignore,ind_xovers_sort] = sort(x./cmAty); Q = union(ind_s_sort(1:m),ind_xovers_sort(end-k+1:end)); case 3 [ignore,ind_xovers_sort] = sort(x./cmAty); Q = ind_xovers_sort(end-k+1:end); case 4 % (ind k smallest s) U (ind m lin ind col) [ignore,Qfull] = sort(cmAty); Qtmp = Qfull(1:k); Q = union(Qtmp,Q_li); end CPU_Q_tot = CPU_Q_tot + cputime - CPUtt_tic; % ** Soft constraints: if sw_soft_constr s = max(tol_soft_constr,s); end % *** STEP 1 % ** Compute the approximate normal matrix: CPUtt_tic = cputime; lQ = length(Q); switch sw_sparse case 0 %CPUt = cputime; D2ATQ = zeros(lQ,m); %cputime-CPUt %CPUt = cputime; for iQ = 1:lQ nloc = Q(iQ); D2ATQ(iQ,:) = x(nloc)/s(nloc)*transpose(A(:,nloc)); end %cputime-CPUt %CPUt=cputime; AD2ATQ = A(:,Q)*D2ATQ; %cputime-CPUt %disp('**') case 1 %CPUt = cputime; D2ATQ = spdiags(x(Q)./s(Q),0,lQ,lQ)*A(:,Q)'; %cputime-CPUt %CPUt = cputime; AD2ATQ = A(:,Q)*spdiags(x(Q)./s(Q),0,lQ,lQ)*A(:,Q)'; %cputime-CPUt %disp('**') end %cputime-CPUtt_tic CPU_normal_tot = CPU_normal_tot + cputime - CPUtt_tic; % ** Diagonal loading if val_loading ~= 0 AD2ATQ = AD2ATQ + val_loading * eye(m); end % ** Symmetrize: !! %AD2ATQ = .5*(AD2ATQ+AD2ATQ'); % !!!! % ** Solve normal equations: CPUtt_tic = cputime; if d_feasible rhs = b; else dual_diff = cmAty-s; rhs = b+A*(1./s.*x.*dual_diff); end if sw_Chol==2 & ~issparse(AD2ATQ); % sw_Chol=2: force Cholinc AD2ATQ = sparse(AD2ATQ); end switch sw_Chol case 0 dy = AD2ATQ\rhs; case {1,2} if issparse(AD2ATQ) R = cholinc(AD2ATQ,'inf'); if any(any(isinf(R))) %disp('Singular PD matrix!!') end else [R,pp] = chol(AD2ATQ); if pp>0 pp test_div = 1; %pause end end if test_div>0 break end warning off dy = R\(R'\rhs); % - p_pi1 in [Meh92] warning on end if d_feasible ds = -A'*dy; else ds = -A'*dy + dual_diff; % -p_s1 in [Meh92] end switch sw_xtilde case 0 xtilde = -x./s.*ds; case 1 xtilde = zeros(n,1); xtilde(Q) = -x(Q)./s(Q).*ds(Q); end dx = xtilde-x; % -p_x1 in [Meh92] CPU_solve_tot = CPU_solve_tot + cputime - CPUtt_tic; if sw_sc_dy & iter==0 dy0 = dy; end ind_s_decr = find(ds<0); switch sw_MPC case 0 % Affine scaling % Nothing to do. case 1 % Predictor-corrector ind_x_decr = find(dx<0); ind_s_decr = find(ds<0); a_aff_p = min(min(-x(ind_x_decr)./dx(ind_x_decr)),1); if isempty(a_aff_p) a_aff_p = Inf; end a_aff_d = min(min(-s(ind_s_decr)./ds(ind_s_decr)),1); if isempty(a_aff_d) a_aff_d = Inf; end % Step MPC-2: compute mu, sigma mu = x'*s/n; mu_aff = (x+a_aff_p*dx)'*(s+a_aff_d*ds)/n; % mdg in [Meh92, p 585] sigma = (mu_aff/mu)^3; % sigma = Meh's (mdg/x's)^nu % sigma*mu = Meh's mu dxds = dx.*ds; if sw_mu_Meh % Do step 4-5 of Mehrotra (1992) p. 585, which is not in % Wright's book. ef = (dx'*s./x.*dx + ds'*x./s.*ds)/(mu*n); % ef in [Meh92, p585] if ef > 1.1 sigma = sigma/min(a_aff_p,a_aff_d); end end %sigma = 0; %dxds = zeros(n,1); % * Version 1: compute the cc's: % Step MPC-3: CPUtt_tic = cputime; rhs_cc = -2*(A*(s.^(-1).*(sigma*mu*ones(n,1)-dxds))); switch sw_Chol case 0 dy_cc = AD2ATQ\rhs_cc; case {1,2} dy_cc = R\(R'\rhs_cc); end % -p_pi2 in [Meh92] ds_cc = -A'*dy_cc; % (+)p_s2 in [Meh92] dx_cc = 2*s.^(-1).*(sigma*mu*ones(n,1)-dxds)-s.^(-1).*x.*ds_cc; % p_x2 in [Meh92] (in Step 3 of [Meh92], read p_x2) CPU_solve_tot = CPU_solve_tot + cputime - CPUtt_tic; switch sw_Meh_SFSOP case 0 % Do it simple, as in Wright's book dx_mpc = dx+.5*dx_cc; dy_mpc = dy+.5*dy_cc; ds_mpc = ds+.5*ds_cc; case 1 % Do it as in Mehrotra (1992) % Compute roots of quadratic polyns to find where the % quadratic leaves the feasible set: % The equation is like x+ gamma_p dx + .5 gamma_d^2 dx_cc = 0 % in the unknown gamma. gamma_p_plus = (-dx+sqrt(dx.^2-2*dx_cc.*dx))./dx_cc; % !! divide by zero gamma_p_minus = (-dx-sqrt(dx.^2-2*dx_cc.*dx))./dx_cc; gamma_p_nonclipped = min([gamma_p_plus(isreal(gamma_p_plus)&(gamma_p_plus>0));... gamma_p_minus(isreal(gamma_p_minus)&(gamma_p_minus>0))]); if ~isempty(gamma_p_nonclipped) gamma_p = min(gamma_p_nonclipped,1); else gamma_p = 1; end gamma_d_plus = (-ds+sqrt(ds.^2-2*ds_cc.*ds))./ds_cc; % !! divide by zero gamma_d_minus = (-ds-sqrt(ds.^2-2*ds_cc.*ds))./ds_cc; gamma_d_nonclipped = min([gamma_d_plus(isreal(gamma_d_plus)&(gamma_d_plus>0));... gamma_d_minus(isreal(gamma_d_minus)&(gamma_d_minus>0))]); if ~isempty(gamma_d_nonclipped) gamma_d = min(gamma_d_nonclipped,1); else gamma_d = 1; end dx_mpc = gamma_p*dx+.5*gamma_p^2*dx_cc; dy_mpc = gamma_d*dy+.5*gamma_d^2*dy_cc; ds_mpc = gamma_d*ds+.5*gamma_d^2*ds_cc; end % sw_Meh_SFSOP xtilde_mpc = x+dx_mpc; % * Version 2: Skip the cc and directly go for mpc. % !! Not ok for infeasible yet. % switch sw_Chol % case 0 % dy_mpc = AD2ATQ\(b-A*(s.^(-1).*(sigma*mu*ones(n,1)-dxds))); % case 1 % dy_mpc = R\(R'\(b-A*(s.^(-1).*(sigma*mu*ones(n,1)-dxds)))); % end % ds_mpc = -A'*dy_mpc; % xtilde_mpc = s.^(-1).*(sigma*mu*ones(n,1)-dxds-x.*ds_mpc); % dx_mpc = xtilde_mpc-x; % Rename the updates: dy_aff = dy; ds_aff = ds; dx_aff = dx; xtilde_aff = xtilde; dy = dy_mpc; ds = ds_mpc; dx = dx_mpc; xtilde = xtilde_mpc; % Step MPC-4-5: apply the updates: % Done later. end % sw_MPC % *** STEP 2 CPUtt_tic = cputime; if sw_sc_dy norm_dy = norm(dy./dy0); else norm_dy = norm(dy); end switch sw_Meh_GTSF case 0 % "Simple" version % ** (i) Compute largest feasible stepsize: ind_s_decr = find(ds<0); if isempty(ind_s_decr) tbar_d = Inf; else tbar_d = min(-s(ind_s_decr)./ds(ind_s_decr)); end switch sw_d_update case 0 that_d = min(beta*tbar_d,1); case 1 that_d = min(max(beta*tbar_d,tbar_d-norm_dy),1); end switch sw_p_update case 0 % Primal update along Delta x. ind_x_decr = find(dx<0); if isempty(ind_x_decr) tbar_p = Inf; else tbar_p = min(-x(ind_x_decr)./dx(ind_x_decr)); end that_p = min(beta*tbar_p,1); % !! Forgot a term... To do... case 1 % Former method (without x_-) % ** (ii) Compute xplus: xplus_tmp = min(max(min((norm_dy)^2+(norm(dx))^2,xunder),xtilde),xmax); dx = xplus_tmp-x; that_p = 1; case 2 % New update method (04 fev 2005), with x_-. xtilde_minus = min(xtilde,0); xplus_tmp = min(max(min((norm_dy)^2+(norm(xtilde_minus))^2,xunder),xtilde),xmax); dx = xplus_tmp-x; that_p = 1; end % ** (iii) Choose new Q: % See beginning of the loop. % ** Ensure decrease of x^Ts: if sw_force_decr_xs dxds = dx'*ds; if dxds > 0 beta_xs = - psi_xs * (x'*that_d*ds+s'*that_p*dx)/... (that_p*that_d*dx'*ds); else beta_xs = Inf; end beta_xs = min(beta_xs,1); else beta_xs = 1; end if beta_xs < 0 disp('beta_xs < 0 !') pause end % ** Updates: xplus = x+beta_xs*that_p*dx; yplus = y+beta_xs*that_d*dy; splus = s+beta_xs*that_d*ds; case 1 % Update as GTSF in [Meh92, p 588] % ?? We don't understand how it could work (notably, why would f % be smaller than 1?) end CPU_step2_tot = CPU_step2_tot + cputime - CPUtt_tic; % *** STOPPING CRITERION CPUtt_tic = cputime; gap_Meh = (c'*xplus-b'*yplus)/(1+abs(b'*yplus)); %resid = norm(b-A*xplus)+norm(xplus.*splus); err = norm(b-A*xplus)/(1+norm(xplus))+norm(c-A'*yplus-splus)/(1+norm(splus))+abs(gap_Meh); % !! Comput for line above to be optimized. %test_conv = (resid < tol_resid); %test_conv = gap_Meh < tol_gap; test_conv = err iter_ubound test_div = 2; end CPU_stop_tot = CPU_stop_tot + cputime - CPUtt_tic; % *** DEBUG if sw_log_scalar err_evol(iter+1) = err; min_x_evol(iter+1) = min(x); min_s_evol(iter+1) = min(s); fn_primal_evol(iter+1) = c'*x; fn_dual_evol(iter+1) = b'*y; end if sw_log_dual y_evol(:,iter+1) = y; end if sw_log_primal x_evol(:,iter+1) = x; s_evol(:,iter+1) = s; end if isnan(err) disp('NaN!') pause end % *** ACTIVATE UPDATES y = yplus; x = xplus; s = splus; iter = iter+1; % *** DISPLAY INFOS if sw_verbose==2 disp('***') iter err max(y) disp(['c-A^Ty>=0? ', num2str(all(c-A'*y>=0))]) disp(['c-A^Ty-s=0? ', num2str(all(abs(c-A'*y-s)<=1e-6))]) that_p that_d beta_xs disp(['xTs = ', num2str(x'*s)]) disp(['Primal resid = ', num2str(norm(b-A*x))]) disp(['Dual resid = ', num2str(norm(c-A'*y-s))]) end end % loop on iterates % ********************************************************* % END LOOP ON ITERATES (y,x,s) % ********************************************************* % *** DEBUG if sw_log_scalar err_evol(iter+1) = err; min_x_evol(iter+1) = min(x); min_s_evol(iter+1) = min(s); fn_primal_evol(iter+1) = c'*x; fn_dual_evol(iter+1) = b'*y; end if sw_log_dual y_evol(:,iter+1) = y; end if sw_log_primal x_evol(:,iter+1) = x; s_evol(:,iter+1) = s; end iter_tot = iter_tot + iter; if test_div break end end % of for rep=1:nb_rep % ********************************************************* % ********************************************************* % END LOOP ON REPETITIONS % ********************************************************* % ********************************************************* CPU_total = (cputime-CPU_tic) disp(['Mean nb iter = ', num2str(iter_tot/nb_rep)]) % ********************************************************* % ********************************************************* % Outputs % ********************************************************* % ********************************************************* varargout{1} = x; varargout{2} = y; if nargout >= 3 % varargout{3} = struct('nb_iter',[],'cpu_total',[],'cpu_normal',[], ... % 'cpu_solve',[],'cpu_step2',[],'cpu_x0',[], ... % 'cpu_Q',[],'cpu_stop',[],'err',[], ... % 'fn_primal',[],'fn_dual',[],'min_x',[], ... % 'min_y',[],'x',[],'y',[],'s',[]); if sw_log_scalar varargout{3}.nb_iter = iter_tot/nb_rep; varargout{3}.cpu_total = CPU_total/nb_rep; varargout{3}.cpu_normal = CPU_normal_tot/nb_rep; varargout{3}.cpu_solve = CPU_solve_tot/nb_rep; varargout{3}.cpu_step2 = CPU_step2_tot/nb_rep; varargout{3}.cpu_x0 = CPU_x0_tot/nb_rep; varargout{3}.cpu_Q = CPU_Q_tot/nb_rep; varargout{3}.cpu_stop = CPU_stop_tot/nb_rep; varargout{3}.err = err_evol; varargout{3}.fn_primal = fn_primal_evol; varargout{3}.fn_dual = fn_dual_evol; varargout{3}.min_x = min_x_evol; varargout{3}.min_s = min_s_evol; end if sw_log_dual varargout{3}.y = y_evol; end if sw_log_primal varargout{3}.x = x_evol; varargout{3}.s = s_evol; end end % Implementation of IPAS method proposed by Andre Tits. % ipas35.m - PA - Started Mon 30 May 2005, CSIT. % Modify labels of figures. % Slightly modify vals_k. % ipas34.m - PA - Started Tue 10 May 2005, CSIT. % Try scale invariance modifs. % ipas33.m - PA - Started Tue 10 May 2005, CSIT. % From *32tt02.m. % ipas32.m - PA - Started Sat 09 Apr 2005, CSIT. % Assess execution times in details, especially for sparse. % Count "cc" computation times in system solve timing. % Modify y0 for scsd1. % ipas31.m - PA - Started Wed 09 Feb 2005, CSIT. % Add comments. % ipas30.m - PA - Started Mon 07 Feb 2005, CSIT. % New version for safety. % ipas29.m - PA - Started Sun 06 Feb 2005, CSIT. % Prepare for automatic runs. % ipas28.m - PA - Started Sun 06 Feb 2005, CSIT. % More tests on Mehrotra heuristics, including non-dual-feasible % case. % Slighly modified definition of 'err' to fit better with [Meh92]. % ipas27.m - PA - Started Sat 05 Feb 2005, CSIT. % Restart working on Mehrotra as in [Mehrotra 1992]. % ipas26.m - PA - Started Thu 03 Feb 2005, CSIT. % New version... % Modify primal (x) update rule to use "x_-". % Force Cholinc. % Correct error in err=... % ipas25.m - PA - Started Sun 17 Oct 2004, College Park. % Force decrease of x's. % ipas24.m - PA - Started Sat 16 Oct 2004, College Park. % Test values of k in decreasing order and stop when failure. % ipas23.m - PA - Started Thu 14 Oct 2004, College Park. % Infeasible version. % Note that Q is chosen from c-A'y, not from s. % Also, mu as in Mehrotra's paper. % ipas22.m - PA - Started Fri 20 Aug 2004, CSIT. % Add diagonal loading heuristic. % Added also was initialization just as in Mehrotra. % Difficulty: y_0 is not necessarily feasible. % ipas21.m - PA - Started Sun 01 Aug 2004, Houckaye. % Heuristic to ensure full-rank of A(:,Q). % ipas20.m - PA - Started Sun 18 Jul 2004, Houckaye. % More tests on CPU times. % ipas19.m - PA - Started Sat 17 Jul 2004, Houckaye. % Test problems FIT1D and FIT2D from Netlib. % ipas18.m - PA - Started Sat 17 Jul 2004, Houckaye. % Test problem scsd6 from Netlib. % ipas17.m - PA - Started Sat 26 Jun 2004, CSIT. % Test sw_problem = 2; % ipas16.m - PA - Started Sat 19 Jun 2004, CSIT. % Other tests. % ipas15.m - PA - Started Fri 18 Jun 2004, CSIT. % New version for security. % ipas14.m - PA - Started Wed 16 Jun 2004, CSIT. % Alternate x0 (one of them like in Mehrotra). % ipas13.m - PA - Started Wed 16 Jun 2004, CSIT. % Trying to debug the Mehrotra version. % ipas12.m - PA - Started Wed 16 Jun 2004, CSIT. % Include Mehrotra predictor-corrector approach. % ipas11.m - PA - Started Tue 15 Jun 2004, CSIT. % Completely erase previous version. % Implement according to [Woessner-Tits, 18 Jul 2003], % with choice between some variants. % % PA Absil, September 3, 1999. % Version ipas08, September 15. % What's new in ipas06: ok for n>2; delta_x <> dx; cost displayed. % In ipas08: new data generator for "random-regular" polytope. % Caution: this m-file contains a clear and a close('all')... % [Meh 92] and [Mehrotra 1992] are "On the implementation of a % primal-dual interior point method", Sanjay Mehrotra, SIOPT 2(4) % 575-601, November 1992.