comparison toolboxes/distance_learning/mlr/util/lcprog.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:e9a9cd732c1e
1 function [z, w, status, z0] = lcprog(M, q, varargin)
2 %LCPROG - Linear complementary programming with Lemke's algorithm.
3 %
4 % [z, w] = lcprog(M, q);
5 % [z, w, status, z0] = lcprog(M, q, varargin);
6 %
7 % Inputs:
8 % M - Matrix (n x n matrix)
9 % q - Vector (n vector)
10 %
11 % Optional Inputs:
12 % Optional name-value pairs are:
13 % 'maxiter' Maximum number of iterations before termination of algorithm (default is (1+n)^3).
14 % 'tiebreak' Method to break ties for pivot selection (default is 'first'). Options are:
15 % 'first' Select pivot with lowest index.
16 % 'last' Select pivot with highest index.
17 % 'random' Select a pivot at random.
18 % 'tolpiv' Pivot tolerance below which a number is considered to be zero (default is 1.0e-9).
19 %
20 % Outputs:
21 % z - Solution vector (n vector)
22 % w - Complementary solution vector (n vector)
23 % status - Status of optimization with values (integer)
24 % 6 Ray termination
25 % 1 Convergence to a solution (normal termination)
26 % 0 Termination prior to convergence
27 % -2 Infeasible problem
28 % -3 Bad pivot to an infeasible solution
29 % z0 - Artificial variable which is 0 upon normal termination (scalar)
30 %
31 % Comments:
32 % Given a matrix M and a vector q, the linear complementary programming (LCP) problem seeks an
33 % orthogonal pair of non-negative vectors w and z such that
34 % w = M * z + q
35 % with
36 % w' * z = 0
37 % w >= 0
38 % z >= 0 .
39 %
40 % The algorithm starts with the problem
41 % w = M * z + q + z0 * 1
42 % with an artificial variable z0 > 0 such that q + z0*1 >= 0. The algorithm goes through a series
43 % of pivot steps that seeks to drive z0 to 0. The algorithm can stop in two ways with either
44 % normal termination or ray termination.
45 %
46 % With normal termination, the artificial variable z0 is zero so that the original problem is
47 % solved.
48 %
49 % With ray termination, the artificial variable z0 is non-negative with "ray" solution in the form
50 % w = wR + lambda * dw
51 % z = zR + lambda * dz
52 % z0 = z0R + lambda * dz0
53 % that satisfies
54 % w = M * z + q + z0 * 1
55 % w' * z = 0
56 % for any lambda >= 0. If ray termination occurs, the returned variables w, z, and z0 are the
57 % points on the ray with lambda = 0.
58 %
59 % If tolpiv is too small, the algorithm may identify a pivot that is effectively zero. If this
60 % situation occurs, the status code -3 is triggered. Try a larger pivot tolerance 'tolpiv' although
61 % a pivot that is too large can trigger false convergence due to failure to find a pivot.
62 %
63
64 %
65 % Copyright 2007 The MathWorks, Inc.
66 % $Revision: 1.1.6.4 $ $ Date: $
67
68 % initialization
69
70 if nargin < 2 || isempty(M) || isempty(q)
71 error('finance:lcprog:MissingInputArgument', ...
72 'One or more missing required input arguments M, q.');
73 end
74
75 q = q(:);
76 n = size(q,1);
77
78 % process name-value pairs (if any)
79
80 if mod(nargin-2,2) ~= 0
81 error('finance:lcprog:InvalidNameValuePair', ...
82 'Invalid name-value pairs with either a missing name or value.');
83 end
84
85 names = { 'maxiter', 'tiebreak', 'tolpiv' }; % names
86 values = { (1 + n)^3, 'first', 1.0e-9 }; % default values
87 try
88 [maxiter, tiebreak, tolpiv] = parsepvpairs(names, values, varargin{:});
89
90 catch E
91 E.throw
92 end
93
94 % check optional arguments
95
96 if maxiter <= 0
97 error('finance:lcprog:NonPositiveInteger', ...
98 'Maximum number of iterations (maxiter) must be a positive integer.');
99 end
100
101 if ~isempty(strmatch(tiebreak,{'default','first'}))
102 tb = 1;
103 elseif ~isempty(strmatch(tiebreak,'last'))
104 tb = 2;
105 elseif ~isempty(strmatch(tiebreak,'random'))
106 tb = 3;
107 else
108 tb = 1;
109 end
110
111 if tolpiv < 2*eps
112 error('finance:lcprog:InvalidTolerance', ...
113 'Unrealistically small tolerance (tolpiv) specified.');
114 end
115
116 % trivial solution
117
118 if all(q >= 0)
119 z = zeros(n,1);
120 w = q;
121 status = 1;
122 z0 = 0;
123 return
124 end
125
126 % set up general problem
127
128 w = zeros(n,1);
129 z = zeros(n,1);
130 u = ones(n,1);
131 z0 = max(-q);
132
133 tableau = [ eye(n), -M, -u, q];
134 basic = (1:n)';
135
136 % initial pivot and initial basis
137
138 r = find(q == min(q),1); % r are pivot rows
139 cx = r; % w(r) leaves the basis
140 c = 2*n + 1; % initial pivot column
141 basic(r) = c; % z0 enters the basis
142
143 % pivot step
144
145 pr = (1/tableau(r,c)) * tableau(r,:);
146 pc = tableau(:,c);
147 tableau = tableau - pc * pr;
148 tableau(r,:) = pr;
149
150 % main loop
151
152 for iter = 2:maxiter
153
154 % get new basic variable
155
156 if cx <= n
157 c = n + cx;
158 elseif cx <= 2*n
159 c = cx - n;
160 end
161
162 % do ratio test
163
164 d = tableau(:,c);
165 mind = NaN(n,1);
166 for i = 1:n
167 if d(i) > tolpiv
168 mind(i) = tableau(i,end)/d(i);
169 end
170 end
171 iind = find(mind == nanmin(mind));
172
173 % ray termination
174
175 if isempty(iind) % cannot find a new basic variable
176 for i = 1:n
177 if basic(i) <= n
178 ii = basic(i);
179 w(ii) = tableau(i,end);
180 z(ii) = 0;
181 elseif basic(i) <= 2*n
182 ii = basic(i) - n;
183 w(ii) = 0;
184 z(ii) = tableau(i,end);
185 else
186 z0 = tableau(i,end);
187 end
188 end
189 if lcprealitycheck(M, q, w, z)
190 status = -3;
191 z = NaN(n,1);
192 w = NaN(n,1);
193 z0 = NaN;
194 else
195 status = 6;
196 end
197 return
198 end
199
200 % identify next basic variable to be replaced using ratio test
201
202 if tb == 3
203 ii = ceil(rand()*numel(iind));
204 if ii < 1
205 ii = 1;
206 end
207 r = iind(ii);
208 elseif tb == 2
209 r = iind(end);
210 elseif tb == 1
211 r = iind(1);
212 end
213 for i = 1:numel(iind) % always select z0 if it is in the index set
214 if basic(iind(i)) == (2*n + 1)
215 r = iind(i);
216 end
217 end
218
219 % new basis
220
221 cx = basic(r); % get variable leaving the basis
222 basic(r) = c; % move new basic variable into the basis
223
224 % pivot step
225
226 pr = (1/tableau(r,c)) * tableau(r,:);
227 pc = tableau(:,c);
228 tableau = tableau - pc * pr;
229 tableau(r,:) = pr;
230
231 if ~isfinite(tableau(1,end)) % trap overflow/underflow
232 warning('finance:lcprog:InfeasibleProblem', ...
233 'Tableau overflow/underflow due to bad pivot.');
234 status = -3;
235 z = NaN(n,1);
236 w = NaN(n,1);
237 z0 = NaN;
238 return
239 end
240
241 % convergence test
242
243 if all(basic <= 2*n) % test if z0 left the basis -> convergence
244 for i = 1:n
245 if basic(i) <= n
246 ii = basic(i);
247 w(ii) = tableau(i,end);
248 z(ii) = 0;
249 else
250 ii = basic(i) - n;
251 w(ii) = 0;
252 z(ii) = tableau(i,end);
253 end
254 end
255 z0 = 0;
256 if lcprealitycheck(M, q, w, z)
257 status = -3;
258 z = NaN(n,1);
259 w = NaN(n,1);
260 z0 = NaN;
261 else
262 status = 1;
263 end
264 return
265 end
266 end
267
268 % too many iterations
269
270 for i = 1:n
271 if basic(i) <= n
272 ii = basic(i);
273 w(ii) = tableau(i,end);
274 z(ii) = 0;
275 elseif basic(i) <= 2*n
276 ii = basic(i) - n;
277 w(ii) = 0;
278 z(ii) = tableau(i,end);
279 else
280 z0 = tableau(i,end);
281 end
282 end
283 if lcprealitycheck(M, q, w, z)
284 status = -3;
285 z = NaN(n,1);
286 w = NaN(n,1);
287 z0 = NaN;
288 else
289 status = 0;
290 end
291
292
293 function notok = lcprealitycheck(M, q, w, z)
294 %LCPREALITYCHECK - Make sure candidate solution z and w is complementary basic feasible.
295
296 u = w - M*z - q;
297
298 if (max(u) - min(u)) > 1
299 warning('finance:lcprog:InfeasibleProblem', ...
300 'Candidate solution is infeasible due to a bad pivot.');
301 notok = true;
302 else
303 notok = false;
304 end
305
306
307 % [EOF]