Mercurial > hg > camir-aes2014
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] |