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