LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
mamap22_fit_fs_multiclass.m
1function [mmap,fF,fS,exact] = mamap22_fit_fs_multiclass(map,p,F,S,classWeights,fsWeights,adjust)
2% Performs approximate fitting of a MMAP given the underlying AMAP(2),
3% the class probabilities (always fitted exactly), the forward moments,
4% and the one-step class transition probabilities.
5% Input
6% - map: second-order AMAP underlying the MAMAP[2]
7% - p: vector of class probabilities
8% - F: vector of forward moments
9% - S: matrix of the class transition probabilities
10% - classWeights: optional vector of weights for each class
11% - fsWeights: optional 2-vector of weights of forward moments and the
12% class transition probabilities
13% Output
14% - mmap: fitted MAMAP[2]
15% - fF: vector of optimal feasible forward moments
16% - fS: vector of optimal feasible class transition probabilities
17
18if (size(map{1},1) ~= 2)
19 error('Underlying MAP must be of second-order.');
20end
21if (map{1}(2,1) ~= 0)
22 error('Underlying MAP must be acyclic');
23end
24if (map{2}(1,2) == 0)
25 form = 1;
26elseif (map{2}(1,1) == 0)
27 form = 2;
28else
29 error('Underlying MAP must be in canonical acyclic form');
30end
31
32fprintf('Fitting MAMAP(2,2) F+S: form = %d\n', form);
33
34% number of classes
35k = length(p);
36if k ~= 2
37 error('Fitting MAMAP(2,2) F+S: only two classes supported');
38end
39
40% default weights to use in the objective function
41if nargin < 5 || isempty(classWeights)
42 classWeights = ones(k,1);
43end
44if nargin < 6 || isempty(fsWeights)
45 fsWeights = ones(2,1);
46end
47if nargin < 7
48 adjust = 1;
49end
50
51% result
52mmap = cell(1,2+k);
53mmap{1} = map{1};
54mmap{2} = map{2};
55
56% get parameters of the underlying AMAP(2)
57h1 = -1/map{1}(1,1);
58h2 = -1/map{1}(2,2);
59r1 = map{1}(1,2) * h1;
60r2 = map{2}(2,2) * h2;
61
62% set tolerance constants
63degentol = 1e-6;
64feastol = 1e-3;
65denumtol = 1e-12;
66
67% generate required coefficients
68if form == 1
69 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
70 fit = @fit_can1;
71elseif form == 2
72 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
73 fit = @fit_can2;
74end
75
76exact = 0;
77
78if (form == 1 && (r1 < degentol || r2 > 1-degentol || abs(h1 - h2 + h2*r1) < degentol )) || ...
79 (form == 2 && (r2 > 1-degentol || abs(h1 - h2 + h2*r1) < degentol ))
80
81 % Transform into a valid second-order Poisson process by perturbing
82 % degenerate parameters to maintain 2-state structure
83 fprintf('Fitting MAMAP(2,2) F+S: perturbing degenerate Poisson to second-order\n');
84 if r1 < degentol
85 r1 = degentol;
86 end
87 if r2 > 1-degentol
88 r2 = 1 - degentol;
89 end
90 if abs(h1 - h2 + h2*r1) < degentol
91 h1 = h2 * (1 - r1) + degentol;
92 end
93 % Reconstruct MAP with perturbed parameters
94 if form == 1
95 map{1} = [-1/h1, r1/h1; 0, -1/h2];
96 map{2} = [(1-r1)/h1, 0; r2/h2, (1-r2)/h2];
97 map = map_normalize(map);
98 mmap{1} = map{1}; mmap{2} = map{2};
99 [G,U,Y] = mamap2m_can1_coefficients(h1,h2,r1,r2);
100 fit = @fit_can1;
101 else
102 map{1} = [-1/h1, r1/h1; 0, -1/h2];
103 map{2} = [0, (1-r1)/h1; r2/h2, (1-r2)/h2];
104 map = map_normalize(map);
105 mmap{1} = map{1}; mmap{2} = map{2};
106 [E,V,Z] = mamap2m_can2_coefficients(h1,h2,r1,r2);
107 fit = @fit_can2;
108 end
109
110elseif form == 2 && r2 < degentol && abs(1-r1) < degentol
111
112 % DEGENERATE PHASE_TYPE
113 fprintf('Fitting MAMAP(2,2) F+S: detected degenerate phase-type form\n');
114
115 % only one degree of freedom: match class probabilites
116 q1 = p(1);
117 q2 = p(1);
118 q3 = p(1);
119
120elseif form == 1 && r2 < degentol
121
122 % CANONICAL PHASE_TYPE
123 fprintf('Fitting MAMAP(2,2) F+S: detected canonical phase-type form\n');
124
125 % convert to phase-type
126 aph = map;
127 aph{2}(2,2) = 0;
128 aph = map_normalize(aph);
129
130 % the forward moments are always equal to the ordinary moments
131 % since the backward moments are not provided as arguments,
132 % we set the backward moments to the ordinary moments as well
133 % TODO: if hypoexponential convert to non-canonical phase-type
134 B = zeros(2,1);
135 B(1) = map_mean(aph);
136 B(2) = map_mean(aph);
137 warning('Fitting MAMAP(2,2) F+S: setting backward moments to ordinary moments, you should try to fit B+S');
138
139 mmap = maph2m_fit_multiclass(aph, p, B, classWeights);
140
141 fF = mmap_forward_moment(mmap, 1);
142 fS = mmap_sigma(mmap);
143
144 return;
145
146elseif (form == 1 && abs(1-r1) < degentol) || ...
147 (form == 2 && abs(1-r1) < degentol)
148
149 % NON-CANONICAL PHASE_TYPE
150 fprintf('Fitting MAMAP(2,2) F+S: detected non-canonical phase-type form\n');
151
152 % two degrees of freedom: fit p and F, not S
153 [q1,q2,q3] = fit_can1_degen(F(1));
154
155 % if unfeasible, perform approximate fitting
156 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
157 % four inequalities, one variable
158 A = zeros(4,1);
159 b = zeros(4,1);
160 % coefficients
161 q2_F = - p(1) / (h1 * (r2-1));
162 q2_0 = + p(1) * h2 / (h1 * (r2-1));
163 q3_F = - p(1) / (h1 * r2);
164 q3_0 = + p(1) * (h1 + h2) / (h1 * r2);
165 % q2 >= 0
166 A(1,1) = -q2_F;
167 b(1) = q2_0;
168 % q2 <= 1
169 A(2,1) = +q2_F;
170 b(2) = 1 - q2_0;
171 % q3 >= 0
172 A(3,1) = -q3_F;
173 b(3) = q3_0;
174 % q3 <= 1
175 A(4,1) = +q3_F;
176 b(4) = 1 - q3_0;
177 % objective function
178 H = 2 / F(1)^2;
179 h = -2 / F(1);
180 % solve
181 fF1 = solve_quadprog();
182 % compute coefficient
183 [q1, q2, q3] = fit_can1_degen(fF1);
184 end
185
186elseif form == 2 && r2 < degentol
187
188 % DEGENERATE CASE FOR gamma < 0
189 fprintf('Fitting MAMAP(2,2) F+S: detected degenerate MMAP form\n');
190
191 if fsWeights(1) > fsWeights(2)
192 fprintf('Fitting MAMAP(2,2) F+S: fitting F\n');
193 [q1,q2,q3] = fit_can2_degen_forward(F(1));
194 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
195 % four inequalities, one variable
196 A = zeros(4,1);
197 b = zeros(4,1);
198 % coefficients
199 q1_F = - p(1) * (r1 - 2) / ((r1-1)*(h1-h2+h2*r1));
200 q1_0 = + p(1) * (r1 - 2)*(h1 + h2*r1) / ((r1-1)*(h1-h2+h2*r1));
201 q2_F = - p(1) * (r1 - 2) / ((h1-h2+h2*r1));
202 q2_0 = + p(1) * (r1 - 2)*h2 / ((h1-h2+h2*r1));
203 % q1 >= 0
204 A(1,1) = -q1_F;
205 b(1) = q1_0;
206 % q1 <= 1
207 A(2,1) = +q1_F;
208 b(2) = 1 - q1_0;
209 % q2 >= 0
210 A(3,1) = -q2_F;
211 b(3) = q2_0;
212 % q2 <= 1
213 A(4,1) = +q2_F;
214 b(4) = 1 - q2_0;
215 % objective function
216 H = 2 / F(1)^2;
217 h = -2 / F(1);
218 % solve
219 fF1 = solve_quadprog();
220 % compute coefficient
221 [q1,q2,q3] = fit_can2_degen_forward(fF1);
222 end
223 else
224 fprintf('Fitting MAMAP(2,2) F+S: fitting S\n');
225 [q1,q2,q3] = fit_can2_degen_transition(S(1,1));
226 if ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
227 % nonlinear constraints: use yalmip
228 varS11 = sdpvar(1,1);
229 options = sdpsettings('verbose',0);
230 boundS11 = [varS11 >= 0, varS11 <= p(1)^2];
231 q1lb = varS11 >= p(1)^2 * (1 - (1-r1)^2);
232 q2ub = varS11 >= p(1)^2 - (1 - p(1))^2;
233 constraints = [boundS11, q1lb, q2ub];
234 obj = (varS11 - S(1,1))^2;
235 sol = solvesdp(constraints, obj, options);
236 if sol.problem ~= 0
237 error('Fitting MAMAP(2,2) F+S: YALMIP = %s\n', sol.info);
238 else
239 fprintf('Fitting MAMAP(2,2) F+S: YALMIP objective = %f\n', double(obj));
240 end
241 % compute coefficient
242 [q1,q2,q3] = fit_can2_degen_transition(double(varS11));
243 end
244 end
245
246else
247
248 % FULL FORM or "GOOD" poisson process
249
250 if (form == 1 && abs(h2-h1*r2) < degentol) || (form == 2 && abs(h1 - h2 - h1*r1 + h1*r1*r2) < degentol)
251 fprintf('Fitting MAMAP(2,2) F+S: detected fittable Poisson process\n')
252 end
253
254 [q1,q2,q3] = fit(F(1), S(1,1));
255
256 % options used to solve the nonlinear problem
257 use_linprog_prepass = 1;
258 tol = 1e-6;
259 optim_space = 'hybrid';
260 %optim_space = 'hybrid-z';
261 %optim_space = 'param';
262 %optim_space = 'char';
263
264 yalmip_nonlinear_opt = sdpsettings(...
265 'verbose',2,...
266 'solver','bmibnb',...
267 'debug',0,...
268 'showprogress',0,...
269 'usex0',1,...
270 'bmibnb.relgaptol',1e-3,...
271 'bmibnb.absgaptol',1e-6,...
272 'bmibnb.maxiter',1000,...
273 'bmibnb.lowrank', 1,...
274 'bmibnb.lpreduce',1,... % without this, crappy lower bounds for some problems
275 'bmibnb.pdtol',-1e-8,... % x >= if x > -pdtol
276 'bmibnb.eqtol',+1e-10,... % x == 0 if abs(x) < +eqtol
277 'bmibnb.roottight',1,...
278 'bmibnb.uppersolver','fmincon-standard',...
279 'fmincon.Algorithm','sqp',...
280 'fmincon.TolCon',1e-6,...
281 'fmincon.TolX',1e-6,...
282 'fmincon.GradObj','on',...
283 'fmincon.GradConstr','on',...
284 'fmincon.Hessian','off',...
285 'fmincon.LargeScale','off');
286
287 % constants
288 M1 = map_mean(map);
289
290 if isfeasible(q1) && isfeasible(q2) && isfeasible(q3)
291 fprintf('Fitting MAMAP(2,2) F+S: exact fit found\n');
292 exact = 1;
293 elseif adjust
294 [q1,q2,q3] = solve_nonlinear(optim_space);
295 end
296
297end % end if/then/else for degenerate forms
298
299% check parameter feasibility
300if adjust && ~(isfeasible(q1) && isfeasible(q2) && isfeasible(q3))
301 error('Fitting MAMAP(2,2) F+S: Feasibility could not be restored: q1 = %e, q2 = %e, q3 = %e', q1, q2, q3);
302end
303% parameters feasible within feastol: restrict to [0,1]
304q1 = fix(q1);
305q2 = fix(q2);
306q3 = fix(q3);
307
308% compute D11,D12,...,D1k
309if form == 1
310 mmap{2+1} = mmap{2} .* [q1 0; q2 q3];
311 mmap{2+2} = mmap{2} .* [1-q1 0; 1-q2 1-q3];
312else
313 mmap{2+1} = mmap{2} .* [0 q1; q2 q3];
314 mmap{2+2} = mmap{2} .* [0 1-q1; 1-q2 1-q3];
315end
316
317fF = mmap_forward_moment(mmap, 1);
318fS = mmap_sigma(mmap);
319
320 function feas = isfeasible(q)
321 feas = q >= -feastol && q <= (1+feastol);
322 end
323
324 function qfix = fix(q)
325 qfix = max(min(q,1),0);
326 end
327
328 function [q1,q2,q3] = fit_can1(vF1,vS11)
329 denum = p(1) * (U(5) * vF1 + U(6));
330 if abs(denum) < denumtol
331 q1 = p(1);
332 q2 = p(1);
333 q3 = p(1);
334 else
335 q2 = (U(1) * vF1^2 * p(1)^2 + U(2) * vF1 * p(1)^2 + U(3) * vS11 + U(4) * p(1)^2)/denum;
336 q1 = -(G(15)*p(1) - vF1*G(3)*p(1) + (G(3)*G(14) - G(2)*G(15)) * q2)/Y(2);
337 q3 = +(G(13)*p(1) - vF1*G(1)*p(1) + (G(1)*G(14) - G(2)*G(13)) * q2)/Y(2);
338 end
339 end
340
341 function [q1,q2,q3] = fit_can1_degen(vF1)
342 q1 = p(1); % meangingless if really degenerate
343 q2 = p(1) * (h2 - vF1) / (h1 * (r2-1));
344 q3 = p(1) * (h1 + h2 - vF1) / (h1 * r2);
345 end
346
347 function [q1,q2,q3] = fit_can2_degen_forward(vF1)
348 q1 = + p(1) * (r1 - 2)*(h1 + h2*r1 - vF1)/((r1-1)*(h1-h2+h2*r1));
349 q2 = - p(1) * (vF1 - h2)*(r1 - 2)/((h1-h2+h2*r1));
350 q3 = p(1); % meangingless if really degenerate
351 end
352
353 function [q1,q2,q3] = fit_can2_degen_transition(vS11)
354 q1 = p(1) + (p(1)^2 - vS11)^(1/2)/(r1 - 1);
355 q2 = p(1) + (p(1)^2 - vS11)^(1/2);
356 q3 = p(1); % meangingless if really degenerate
357 end
358
359 function [q1,q2,q3] = fit_can2(vF1,vS11)
360 denum = (V(5) * vF1 * p(1) + V(6) * p(1));
361 if abs(denum) < denumtol
362 q1 = p(1);
363 q2 = p(1);
364 q3 = p(1);
365 else
366 q3 = (V(1) * vF1^2 * p(1)^2 + V(2) * vF1 * p(1)^2 + V(3) * p(1)^2 + V(4) * vS11)/denum;
367 q1 = -(E(13)*p(1) - vF1*E(2)*p(1) + (E(2)*E(14) - E(3)*E(13)) * q3)/Z(2);
368 q2 = +(E(12)*p(1) - vF1*E(1)*p(1) + (E(1)*E(14) - E(3)*E(12)) * q3)/Z(2);
369 end
370 end
371
372 function [pexp,pFexp,Sexp] = get_characteristics(q1,q2,q3)
373 if form == 1
374 pexp = G(1)*q1+G(2)*q2+G(3)*q3;
375 pFexp = G(13)*q1+G(14)*q2+G(15)*q3;
376 Sexp = G(4)*q1^2 + G(5)*q1*q2 + G(6)*q1*q3 + G(7)*q2^2 + G(8)*q2*q3 + G(9)*q3^2;
377 else
378 pexp = E(1)*q1+E(2)*q2+E(3)*q3;
379 pFexp = (E(12)*q1+E(13)*q2+E(14)*q3);
380 Sexp = E(4)*q1*q2 + E(5)*q1*q3 + E(6)*q2^2 + E(7)*q2*q3 + E(8)*q3^2;
381 end
382 end
383
384 function opt = get_yalmip_linear_options()
385 % we do not set solver so that YALMIP picks the best
386 opt = sdpsettings('verbose',0);
387 end
388
389 function [q1,q2,q3,obj] = solve_nonlinear(optim_space)
390
391 fprintf('Fitting MAMAP(2,2) F+S: running approximate fitting (nonlinear)\n');
392
393 if strcmp(optim_space, 'param')
394 [q1,q2,q3,obj] = solve_nonlinear_param();
395 else
396 if strcmp(optim_space, 'hybrid')
397 solve_nonlinear_func = @solve_nonlinear_hybrid;
398 elseif strcmp(optim_space, 'hybrid-z')
399 solve_nonlinear_func = @solve_nonlinear_hybrid_z;
400 elseif strcmp(optim_space, 'char')
401 solve_nonlinear_func = @solve_nonlinear_char;
402 else
403 error('Fitting MAMAP(2,2) F+S: invalid value for option "optim_space"');
404 end
405 % trivial solution
406 eobj = make_objective(M1, p(1)^2);
407 fprintf('Fitting MAMAP(2,2) F+S: F1 == M1, objective = %e\n', eobj);
408 % left solution
409 [lfeas,lobj,lF1,lS11] = solve_nonlinear_func('left');
410 if lfeas
411 fprintf('Fitting MAMAP(2,2) F+S: F1 < M1, objective = %e\n', lobj);
412 else
413 fprintf('Fitting MAMAP(2,2) F+S: F1 < M1 infeasible\n');
414 end
415 % right solution
416 [rfeas,robj,rF1,rS11] = solve_nonlinear_func('right');
417 if rfeas
418 fprintf('Fitting MAMAP(2,2) F+S: F1 > M1, objective = %e\n', robj);
419 else
420 fprintf('Fitting MAMAP(2,2) F+S: F1 > M1 infeasible\n');
421 end
422 % pick best solution
423 if (~lfeas && ~rfeas) || (eobj < lobj && eobj < robj)
424 obj = eobj;
425 q1 = p(1);
426 q2 = p(1);
427 q3 = p(1);
428 elseif ~rfeas || lobj < robj
429 obj = lobj;
430 [q1,q2,q3] = fit(lF1, lS11);
431 else
432 obj = robj;
433 [q1,q2,q3] = fit(rF1, rS11);
434 end
435 end
436
437 end
438
439% used for non-degenerate cases: parmeter space
440 function [q1,q2,q3,obj] = solve_nonlinear_param()
441 % find initial feasible solution
442 vq = sdpvar(3,1);
443 z = sdpvar(2,1);
444 % define expressions
445 [pexp,pFexp,Sexp] = get_characteristics(vq(1),vq(2),vq(3));
446 % set constraints
447 cstr_exact_p = pexp == p(1);
448 cstr_tighten_F = -z(1) <= (pFexp - p(1)*F(1))/(p(1)*F(1)) <= z(1);
449 cstr_tighten_S = -z(2) <= (Sexp - S(1,1))/S(1,1) <= z(2);
450 cstr = [0 <= vq(1) <= 1, ...
451 0 <= vq(2) <= 1, ...
452 0 <= vq(3) <= 1, ...
453 cstr_exact_p, ...
454 cstr_tighten_F,...
455 cstr_tighten_S,...
456 z(1) >= 0, z(2) >= 0];
457 % set objective
458 zobj = fsWeights(1) * z(1)^2 + fsWeights(2) * z(2)^2;
459 % run solver
460 zsol = solvesdp(cstr, zobj, yalmip_nonlinear_opt);
461 % check output
462 if zsol.problem == 0
463 q1 = double(vq(1));
464 q2 = double(vq(2));
465 q3 = double(vq(3));
466 obj = double(zobj);
467 fprintf('Fitting MAMAP(2,2) F+S: solver (parameter space) objective = %e\n', obj);
468 else
469 fname = tempname;
470 save(fname,'map','p','F','S');
471 error('Fitting MAMAP(2,2) F+S: solver (parameter space) error: %s, input saved to %s\n', zsol.info, fname);
472 end
473 end
474
475% used for non-degenerate cases: hybrid space
476 function [feas,bobj,bF1,bS11] = solve_nonlinear_hybrid(side)
477 vF1 = sdpvar(1,1);
478 vS11 = sdpvar(1,1);
479 if form == 1
480 vq2 = sdpvar(1,1);
481 scale = U(5);
482 q1exp = -(G(15)*p(1) - vF1*G(3)*p(1) + vq2*(G(14)*G(3)-G(15)*G(2)))/Y(2);
483 q2num = U(1)*vF1^2*p(1)^2 + U(2)*vF1*p(1)^2 + U(3)*vS11 + U(4)*p(1)^2;
484 q2den = p(1)*(U(5)*vF1 + U(6));
485 q3exp = +(G(13)*p(1) - vF1*G(1)*p(1) + vq2*(G(14)*G(1)-G(13)*G(2)))/Y(2);
486 hcstr = [0 <= q1exp <= 1, 0 <= vq2 <= 1, vq2*q2den/scale == q2num/scale, 0 <= q3exp <= 1, 0 <= vS11 <= 1, vF1 >= 0];
487 else
488 vq3 = sdpvar(1,1);
489 scale = V(5);
490 q1exp = -(E(13)*p(1) - vF1*E(2)*p(1) + vq3*(E(14)*E(2)-E(13)*E(3)))/Z(2);
491 q2exp = +(E(12)*p(1) - vF1*E(1)*p(1) + vq3*(E(14)*E(1)-E(12)*E(3)))/Z(2);
492 q3num = V(1)*vF1^2*p(1)^2 + V(2)*vF1*p(1)^2 + V(3)*p(1)^2 + V(4)*vS11;
493 q3den = p(1)*(V(5)*vF1 + V(6));
494 hcstr = [0 <= q1exp <= 1, 0 <= q2exp <= 1, vq3*q3den/scale == q3num/scale, 0 <= vq3 <= 1, 0 <= vS11 <= 1, vF1 >= 0];
495 end
496 if strcmp(side,'left')
497 hcstr = [hcstr, vF1 <= M1-tol];
498 else
499 hcstr = [hcstr, vF1 >= M1+tol];
500 end
501 hobj = make_objective(vF1,vS11);
502 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
503 if hsol.problem == 0
504 fprintf('Fitting MAMAP(2,2) F+S: solver (hybrid space) objective = %f\n', double(hobj));
505 feas = 1;
506 bobj = double(hobj);
507 bF1 = double(vF1);
508 bS11 = double(vS11);
509 elseif hsol.problem == 1 || hsol.problem == 12
510 fprintf('Fitting MAMAP(2,2) F+S: program is infeasible\n');
511 feas = 0;
512 bobj = nan;
513 bF1 = nan;
514 bS11 = nan;
515 else
516 fname = tempname;
517 save(fname,'map','p','F','S');
518 error('Fitting MAMAP(2,2) F+S: solver (hybrid space) error: %s, input saved to %s\n', hsol.info, fname);
519 end
520 end
521
522% used for non-degenerate cases: hybrid space with z variable and implicit vS11
523 function [feas,bobj,bF1,bS11] = solve_nonlinear_hybrid_z(side)
524 vF1 = sdpvar(1,1);
525 z = sdpvar(1,1);
526 if form == 1
527 vq2 = sdpvar(1,1);
528 q1exp = -(G(15)*p(1) - vF1*G(3)*p(1) + vq2*(G(14)*G(3)-G(15)*G(2)))/Y(2);
529 q2den = p(1)*(U(5)*vF1 + U(6));
530 q3exp = +(G(13)*p(1) - vF1*G(1)*p(1) + vq2*(G(14)*G(1)-G(13)*G(2)))/Y(2);
531 S11exp = (vq2*q2den - p(1)^2*(U(1)*vF1^2 + U(2)*vF1 + U(4)))/U(3);
532 tighten = -z <= S11exp - S(1,1) <= +z;
533 hcstr = [0 <= q1exp <= 1, 0 <= vq2 <= 1, 0 <= q3exp <= 1, vF1 >= 0, tighten];
534 else
535 vq3 = sdpvar(1,1);
536 q1exp = -(E(13)*p(1) - vF1*E(2)*p(1) + vq3*(E(14)*E(2)-E(13)*E(3)))/Z(2);
537 q2exp = +(E(12)*p(1) - vF1*E(1)*p(1) + vq3*(E(14)*E(1)-E(12)*E(3)))/Z(2);
538 q3den = p(1)*(V(5)*vF1 + V(6));
539 S11exp = (vq3*q3den - p(1)^2*(V(1)*vF1^2 + V(2)*vF1 + V(3)))/V(4);
540 tighten = -z <= S11exp - S(1,1) <= +z;
541 hcstr = [0 <= q1exp <= 1, 0 <= q2exp <= 1, 0 <= vq3 <= 1, vF1 >= 0, tighten];
542 end
543 if strcmp(side,'left')
544 hcstr = [hcstr, vF1 <= M1-tol];
545 else
546 hcstr = [hcstr, vF1 >= M1+tol];
547 end
548 hobj = fsWeights(1)*(vF1/F(1)-1)^2 + fsWeights(2)*(z/S(1,1))^2;
549 hsol = solvesdp(hcstr, hobj, yalmip_nonlinear_opt);
550 if hsol.problem == 0
551 fprintf('Fitting MAMAP(2,2) F+S: solver (hybrid-z space) objective = %f\n', double(hobj));
552 feas = 1;
553 bobj = double(hobj);
554 bF1 = double(vF1);
555 bS11 = double(S11exp);
556 elseif hsol.problem == 1 || hsol.problem == 12
557 fprintf('Fitting MAMAP(2,2) F+S: program is infeasible\n');
558 feas = 0;
559 bobj = nan;
560 bF1 = nan;
561 bS11 = nan;
562 else
563 fname = tempname;
564 save(fname,'map','p','F','S');
565 error('Fitting MAMAP(2,2) F+S: solver (hybrid-z space) error: %s, input saved to %s\n', hsol.info, fname);
566 end
567 end
568
569% used for non-degenerate cases: characteristic space
570 function [feas,bobj,bF1,bS11] = solve_nonlinear_char(side)
571 is_left = 0;
572 if strcmp(side,'left')
573 fprintf('Fitting MAMAP(2,2) F+S: optimizing for F11 < M1\n');
574 is_left = 1;
575 else
576 fprintf('Fitting MAMAP(2,2) F+S: optimizing for F11 > M1\n');
577 end
578 % find initial feasible solution
579 if use_linprog_prepass
580 % parameter variables vq and auxiliary variables
581 vq = sdpvar(3,1);
582 z = sdpvar(1,1);
583 % define expressions
584 [pexp,pFexp,Sexp] = get_characteristics(vq(1),vq(2),vq(3));
585 % set constraints
586 if is_left
587 cstr_side = pFexp <= pexp*(M1-tol);
588 else
589 cstr_side = pFexp >= pexp*(M1+tol);
590 end
591 cstr_exact_p = pexp == p(1);
592 cstr_tighten = -z <= pFexp-p(1)*F(1) <=z;
593 fcstr = [0 <= vq(1) <= 1, ...
594 0 <= vq(2) <= 1, ...
595 0 <= vq(3) <= 1, ...
596 cstr_exact_p, ...
597 cstr_side,...
598 cstr_tighten,...
599 z >= 0];
600 % run linear programming solver
601 lsol = solvesdp(fcstr,z, get_yalmip_linear_options());
602 % check output
603 if lsol.problem == 0
604 feas = 1;
605 iF1 = double(pFexp / pexp);
606 iS11 = double(Sexp);
607 elseif lsol.problem == 1 || lsol.problem == 12
608 fprintf('Fitting MAMAP(2,2) F+S: linear program is infeasible\n');
609 feas = 0;
610 else
611 fname = tempname;
612 save(fname,'map','p','F','S');
613 error('Fitting MAMAP(2,2) F+S: linear program error: %s, input saved to %s\n', lsol.info, fname);
614 end
615 else
616 % assume feasible
617 feas = 1;
618 end
619 % if feasible, solve nonlinear program
620 if feas
621 % declare variables for optimization in characteristic space
622 vF1 = sdpvar(1,1);
623 vS11 = sdpvar(1,1);
624 % initialize variables
625 if use_linprog_prepass
626 assign(vF1,iF1);
627 assign(vS11,iS11);
628 end
629 % define objective function
630 cobj = make_objective(vF1, vS11);
631 % define constraints
632 if is_left
633 if form == 1
634 [cstr,~] = make_constraints_can1(p(1), vF1, vS11);
635 else
636 [cstr,~] = make_constraints_can2(p(1), vF1, vS11);
637 end
638 else
639 if form == 1
640 [~,cstr] = make_constraints_can1(p(1), vF1, vS11);
641 else
642 [~,cstr] = make_constraints_can2(p(1), vF1, vS11);
643 end
644 end
645 % solve nonlinear problem
646 csol = solvesdp(cstr, cobj, yalmip_nonlinear_opt);
647 % check result
648 if csol.problem ~= 0
649 fname = tempname;
650 save(fname,'map','p','F','S');
651 error('Fitting MAMAP(2,2) F+S: solver (characteristic space) error: %s, input saved to %s\n', csol.info, fname);
652 else
653 bobj = double(cobj);
654 bF1 = double(vF1);
655 bS11 = double(vS11);
656 fprintf('Fitting MAMAP(2,2) F+S: solver (characteristic space) objective = %e\n', double(cobj));
657 end
658 else
659 % infeasible subproblem
660 bobj = nan;
661 bF1 = nan;
662 bS11 = nan;
663 end
664 end
665
666 function obj = make_objective(vF1, vS11)
667 obj = classWeights(1) * fsWeights(1) * (vF1/F(1) - 1)^2 + ...
668 classWeights(1) * fsWeights(2) * (vS11/S(1,1) - 1)^2;
669 end
670
671 function [q1n,q1d,q2n,q2d,q3] = make_q_can1(p, vF1, vS11)
672 % define coefficients of polynomials
673 q1n_F = p^2*(r1 - 1)*(r1*r2 - r2 + 1);
674 q1n_s = -r1*(h1 - h2 + h2*r1);
675 q1n_1 = h1*p^2*(r1*r2 - r2 + 1);
676 q1d_F = p*(r1 - 1)*(r1*r2 - r2 + 1);
677 q1d_1 = -p*(r1 - 1)*(h1 - h1*r2 + h2*r1);
678 q2n_Fsq = -p^2*(r1*r2 - r2 + 1)^2;
679 q2n_F = p^2*(r1*r2 - r2 + 1)*(2*h1 - h1*r1 - 2*h1*r2 + 3*h2*r1 - h2*r1^2 + h2*r1^2*r2 + h1*r1*r2 - h2*r1*r2);
680 q2n_s = -r1*(r2 - 1)*(h1 - h2 + h2*r1)^2;
681 q2n_1 = -p^2*(r1*r2 - r2 + 1)*(h2^2*r1 - h1^2*r2 + h1^2 + h1*h2*r1 - h1*h2*r1*r2);
682 q2d_F = p*r1*(r2 - 1)*(r1*r2 - r2 + 1)*(h1 - h2 + h2*r1);
683 q2d_1 = -p*r1*(r2 - 1)*(h1 - h1*r2 + h2*r1)*(h1 - h2 + h2*r1);
684 q3_F = -(p*(r1*r2 - r2 + 1))/(r1*r2*(h1 + h2*(r1 - 1)));
685 q3_1 = (p*(h1 + h2*r1)*(r1*r2 - r2 + 1))/(r1*r2*(h1 - h2 + h2*r1));
686 % return expressions
687 q1n = q1n_F * vF1 + q1n_s * vS11 + q1n_1;
688 q1d = q1d_F * vF1 + q1d_1;
689 q2n = q2n_Fsq * vF1^2 + q2n_F * vF1 + q2n_s * vS11 + q2n_1;
690 q2d = q2d_F * vF1 + q2d_1;
691 q3 = q3_F * vF1 + q3_1;
692 end
693
694 function [lcstr,rcstr] = make_constraints_can1(p, vF1, vS11)
695
696 % get fitting expressions
697 [q1n,q1d,q2n,q2d,q3] = make_q_can1(p, vF1, vS11);
698
699 % these are in common for the two subproblems
700 q3lb = q3 >= 0;
701 q3ub = q3 <= 1;
702
703 scale = 1/abs(U(5));
704 %scale = 1/abs(q2d{M1-tol});
705
706 % left constraints: F(1) < M1
707 q1lb = q1n >= 0;
708 q1ub = q1n <= q1d;
709 if h2 < h1/(1-r1)
710 % do not change direction of inequalities for q2
711 q2lb = scale*(q2n) >= 0;
712 q2ub = scale*(q2n) <= scale*(q2d);
713 else
714 % change direction of inequalities for q2
715 q2lb = scale*(q2n) <= 0;
716 q2ub = scale*(q2n) >= scale*(q2d);
717 end
718 F1bound = vF1 <= M1-tol;
719 lcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
720
721 % right constraints: F(1) > M1
722 q1lb = q1n <= 0;
723 q1ub = q1n >= q1d;
724 if h2 > h1/(1-r1)
725 % do not change direction of inequalities for q2
726 q2lb = scale*(q2n) >= 0;
727 q2ub = scale*(q2n) <= scale*(q2d);
728 else
729 % change direction of inequalities for q2
730 q2lb = scale*(q2n) <= 0;
731 q2ub = scale*(q2n) >= scale*(q2d);
732 end
733 F1bound = vF1 >= M1+tol;
734 rcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
735 end
736
737 function [q1n,q1d,q2,q3n,q3d] = make_q_can2(p, vF1, vS11)
738 % define coefficients of polynomials
739 q1n_F = p^2*(r1 - 1)*(r1 + r2 - r1*r2 - 2);
740 q1n_s = h1 - h2 + h2*r1;
741 q1n_1 = h1*p^2*(r1 + r2 - r1*r2 - 2);
742 q1d_F = p*(r1 - 1)*(r1 + r2 - r1*r2 - 2);
743 q1d_1 = p*(r1 - 1)*(h1 + h2 - h1*r2);
744 q2_F = p*(r1 + r2 - r1*r2 - 2)/(h2 - h1 + h1*r2 - h2*r1 - h2*r2 + h2*r1*r2);
745 q2_1 = -h2*p*(r1 + r2 - r1*r2 - 2)/(h2 - h1 + h1*r2 - h2*r1 - h2*r2 + h2*r1*r2);
746 q3n_Fsq = p^2*(r1 + r2 - r1*r2 - 2)^2;
747 q3n_F = p^2*(r1 + r2 - r1*r2 - 2)*(2*h1 + 2*h2 - h1*r2 - h2*r2 + h2*r1*r2);
748 q3n_s = -(r2 - 1)*(h1 - h2 + h2*r1)^2;
749 q3n_1 = -h2*p^2*(2*h1 - h1*r2 + h2*r1)*(r1 + r2 - r1*r2 - 2);
750 q3d_F = p*r2*(h1 - h2 + h2*r1)*(r1 + r2 - r1*r2 - 2);
751 q3d_1 = p*r2*(h1 + h2 - h1*r2)*(h1 - h2 + h2*r1);
752 % return expressions
753 q1n = q1n_F * vF1 + q1n_s * vS11 + q1n_1;
754 q1d = q1d_F * vF1 + q1d_1;
755 q2 = q2_F * vF1 + q2_1;
756 q3n = q3n_Fsq * vF1^2 + q3n_F * vF1 + q3n_s * vS11 + q3n_1;
757 q3d = q3d_F * vF1 + q3d_1;
758 end
759
760 function [lcstr,rcstr] = make_constraints_can2(p, vF1, vS11)
761
762 % get fitting expressions
763 [q1n,q1d,q2,q3n,q3d] = make_q_can2(p, vF1, vS11);
764
765 % these are in common for the two subproblems
766 q2lb = q2 >= 0;
767 q2ub = q2 <= 1;
768
769 scale = 1/abs(V(5));
770 %scale = 1/abs(q3d{M1-tol});
771
772 % left constraints: F1 < M1
773 q1lb = q1n <= 0;
774 q1ub = q1n >= q1d;
775 if (h1 - h2 + h2*r1) < 0
776 q3lb = scale*(q3n) <= 0;
777 q3ub = scale*(q3n) >= scale*(q3d);
778 else
779 q3lb = scale*(q3n) >= 0;
780 q3ub = scale*(q3n) <= scale*(q3d);
781 end
782 F1bound = vF1 <= M1-tol;
783 lcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
784
785 % rigt costraints: F1 > M1
786 q1lb = q1n >= 0;
787 q1ub = q1n <= q1d;
788 if (h1 - h2 + h2*r1) < 0
789 q3lb = scale*(q3n) >= 0;
790 q3ub = scale*(q3n) <= scale*(q3d);
791 else
792 q3lb = scale*(q3n) <= 0;
793 q3ub = scale*(q3n) >= scale*(q3d);
794 end
795 F1bound = vF1 >= M1+tol;
796 rcstr = [q1lb,q1ub,q2lb,q2ub,q3lb,q3ub,F1bound,vS11 >= 0, vS11 <= 1];
797 end
798
799% used for degenerate case
800 function x = solve_quadprog()
801 fprintf('Fitting MAMAP(2,2) F+S: running quadratic programming solver...\n');
802 options = optimset('Algorithm','interior-point-convex','Display','none');
803 %[x,fx,xflag] = quadprog(H, h, A, b, [], [], [], [], [], options);
804 lb = 1e-6*ones( size(A,2),1);
805 ub = 1e6*ones( size(A,2),1);
806 [x,fx,xflag]=QP(H, h, A, b, Aeq, beq, lb, ub, options);
807
808 if xflag ~= 1
809 error('Quadratic programming solver failed: %d\n', exit);
810 end
811 fit_error = fx + length(x);
812 fprintf('Fitting MAMAP(2,2) F+S: error = %f\n', fit_error);
813 end
814
815end