-
Notifications
You must be signed in to change notification settings - Fork 5
/
recspathmcp.m
229 lines (190 loc) · 6.15 KB
/
recspathmcp.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
function [z,f,exitflag,J,mu] = recspathmcp(z,l,u,cpfj,nnzJ,A,b,t,mu)
% RECSPATHMCP solves a polyhedrally constrained variational inequality using PATH
%
% Z = RECSPATHMCP(Z,L,U,CPFJ) tries to solve, using Z as a starting point, the mixed
% complementarity problem of the form:
% L =Z => F(Z)>0,
% L<=Z<=U => F(Z)=0,
% Z =U => F(Z)<0.
% L and U are the lower and upper bounds on Z. RECSPATHMCP returns Z the solution.
% CPFJ is the name (without .m-extension) of the m-file for evaluating the
% function F and its Jacobian J. The m-file must be supplied (where default name
% is 'mcp_funjac.m' unless stated otherwise in the variable
% CPFJ). 'mcp_funjac.m' contains function [F,J,DOMERR]=MCP_FUNJAC(Z,JACFLAG)
% that computes the function F and if JACFLAG=1 the sparse Jacobian J at the
% point Z. DOMERR returns the number of domain violations.
% Solver options can be defined through an option file present in the working
% directory and named 'path.opt'. Many options are described in the following file:
% http://www.cs.wisc.edu/~ferris/path/options.pdf
% RECSPATHMCP returns also a log file named 'logfile.tmp'. From MATLAB, it can be
% displayed by 'type logfile.tmp'.
%
% Z = RECSPATHMCP(Z,L,U,CPFJ,NNZJ) uses NNZJ the number of non-zero elements in the
% Jacobian to initialize the memory allocation for the Jacobian. If NNZJ is not
% provided, it is evaluated at the starting point Z.
%
% Z = RECSPATHMCP(Z,L,U,CPFJ,NNZJ,A,B,T,MU)
% A - constraint matrix
% B - right hand side of the constraints
% T - types of the constraints
% <0 : less than or equal
% =0 : equal to
% >0 : greater than or equal
% We have AZ ? B, ? is the type of constraint
% MU - multipliers on the constraints
%
% [Z,F] = RECSPATHMCP(Z,L,U,CPFJ,...) returns F the function evaluation at the
% solution.
%
% [Z,F,EXITFLAG] = RECSPATHMCP(Z,L,U,CPFJ,...) returns EXITFLAG that describes
% the exit conditions. Possible values listed below.
% 1 : solved
% 0 : failed to solve
%
% [Z,F,EXITFLAG,J] = RECSPATHMCP(Z,L,U,CPFJ,...) returns J the Jacobian evaluation
% at the solution.
%
% [Z,F,EXITFLAG,J,MU] = RECSPATHMCP(Z,L,U,CPFJ,NNZJ,A,B,T,MU) returns MU the
% multipliers on the constraints at the solution.
%
% For more information, see the following references
% Dirkse, S. P. and Ferris, M. C. (1995), The PATH solver: A non-monotone
% stabilization scheme for mixed complementarity problems, Optimization Methods
% and Software 5, 123-156. DOI: <a href="http://dx.doi.org/10.1080/10556789508805606">10.1080/10556789508805606</a>
% Ferris, M. C. and Munson, T. S. (1999), Interfaces to PATH 3.0: Design,
% Implementation and Usage, Computational Optimization and Applications 12,
% 207-227. DOI: <a href="http://dx.doi.org/10.1023/A:1008636318275">10.1023/A:1008636318275</a>
% Munson, T. S. (2002), Algorithms and Environments for Complementarity, PhD
% thesis, University of Wisonsin-Madison.
% Copyright (C) Michael C. Ferris and Todd S. Munson
% This is a modification by Christophe Gouel of the original file pathmcp.m, which can be
% downloaded from: http://pages.cs.wisc.edu/~ferris/path.html.
%% Initialization
Big = 1e20;
if (nargin < 1)
error('one input arguments required for mcp(z)');
end
z = full(z(:));
n = length(z);
if (n == 0)
error('empty model');
end
if (nargin < 2 || isempty(l))
l = zeros(n,1);
end
if (nargin < 3 || isempty(u))
u = Big*ones(n,1);
end
l = full(l(:));
u = full(u(:));
if (length(l) ~= n || length(u) ~= n)
error('Input arguments are of incompatible sizes');
end
if any(u-l<0)
error('Some upper bounds are inferior to their corresponding lower bounds')
end
l = max(l,-Big*ones(n,1));
u = min(u,Big*ones(n,1));
z = min(max(z,l),u);
if (nargin < 4 || isempty(cpfj))
cpfj = 'mcp_funjac';
end
m = 0;
mu = [];
l_p = [];
u_p = [];
%%
if (nargin > 5)
%% With Polyhedral constraints
if (nargin < 7)
error('Polyhedral constraints require A and b');
end
if (~issparse(A))
A = sparse(A);
end
b = full(b(:));
m = length(b);
if (m > 0)
[am, an] = size(A);
if (am ~= m || an ~= n)
error('Polyhedral constraints of incompatible sizes');
end
if (nargin < 8 || isempty(t))
t = ones(m,1);
end
if (nargin < 9 || isempty(mu))
mu = zeros(m,1);
end
t = full(t(:)); mu = full(mu(:));
if (length(t) ~= m || length(mu) ~= m)
error('Polyhedral input arguments are of incompatible sizes');
end
l_p = -Big*ones(m,1);
u_p = Big*ones(m,1);
idx = find(t > 0);
if (length(idx) > 0)
l_p(idx) = zeros(length(idx),1);
end
idx = find(t < 0);
if (length(idx) > 0)
u_p(idx) = zeros(length(idx),1);
end
mu = min(max(mu,l_p),u_p);
else
if (nargin >= 9 && ~isempty(mu))
error('No polyhedral constraints -- multipliers set.');
end
if (nargin >= 8 && ~isempty(t))
error('No polyhedral constraints -- equation types set.');
end
end
else
A = [];
end
%% Check for domain error at starting point and Jacobian
% this is a fix, nnz may be bigger than this
[~,~,domerr1] = feval(cpfj,z,0);
[~,J,domerr2] = feval(cpfj,z+1e-5*ones(size(z))+1e-5*abs(z),1);
domerr = max(domerr1,domerr2);
if (domerr > 0)
[~,J] = feval(cpfj,z,1);
end
if (domerr > 0)
error([cpfj ' not defined at starting point']);
end
if ~issparse(J)
error([cpfj ' must return a sparse Jacobian']);
end
if (nargin<5 || isempty(nnzJ))
nnzJ = nzmax(J)*1.05;
end
row = n + m;
ele = nnzJ + 2*nzmax(A);
%% Solve the problem
init = [z; mu];
low = [l; l_p];
upp = [u; u_p];
if m > 0
global mcp_vifunc;
global mcp_viconn;
global mcp_viconm;
global mcp_viconA;
global mcp_viconb;
mcp_vifunc = cpfj;
mcp_viconn = n;
mcp_viconm = m;
mcp_viconA = A;
mcp_viconb = b;
[exitflag, ~, f, J] = mcppath(row, ele, init, low, upp, 'mcp_vifunjac');
else
[exitflag, ~, f, J] = mcppath(row, ele, init, low, upp, cpfj);
end
mu = [];
z = init;
%%
if m > 0
mu = init(n+1:n+m);
z = init(1:n);
J = J(1:n,1:n);
f = f(1:n) + A'*mu;
end