5#ifndef LINE_API_MAM_M3PP2M_FITC_APPROX_H
6#define LINE_API_MAM_M3PP2M_FITC_APPROX_H
122struct M3ppSplitCoeffs {
138M3ppSplitCoeffs<T> m3pp_split_coeffs_dv(
const T& l1,
const T& l2,
const T& r1,
const T& r2,
144 const T SH = (one - num_exp(T(-(r1 + r2) * t))) / two;
146 const T BR = two * l1 * SH - two * l2 * SH - l1 * r1 * t - l1 * r2 * t + l2 * r1 * t +
148 const T DEN1 = l1 * r2 * (r1 + r2) * BR;
149 const T BR2 = l2 * l2 * r1 * r1 * t - two * l2 * l2 * r1 * SH - l1 * l2 * r1 * r1 * t +
150 l2 * l2 * r1 * r2 * t + two * l1 * l2 * r1 * SH - l1 * l2 * r1 * r2 * t;
151 const T DEN2 = (r1 + r2) * BR2;
154 four * r1 * pw(r2, 3) + pw(r2, 4);
155 const T CN = l1 * pw(r2, 4) * t + l2 * pw(r1, 4) * t + three * l1 * r1 * pw(r2, 3) * t +
156 l1 * pw(r1, 3) * r2 * t + l2 * r1 * pw(r2, 3) * t + three * l2 * pw(r1, 3) * r2 * t +
157 three * l1 * r1 * r1 * r2 * r2 * t + two * l1 * l1 * r1 * r2 * r2 * t +
158 two * l1 * l1 * r1 * r1 * r2 * t + three * l2 * r1 * r1 * r2 * r2 * t +
159 two * l2 * l2 * r1 * r2 * r2 * t + two * l2 * l2 * r1 * r1 * r2 * t -
160 four * l1 * l1 * r1 * r2 * SH - four * l2 * l2 * r1 * r2 * SH -
161 four * l1 * l2 * r1 * r2 * r2 * t - four * l1 * l2 * r1 * r1 * r2 * t +
164 M3ppSplitCoeffs<T> q;
165 q.q1_a = (pw(r1, 4) * t / two + pw(r2, 4) * t / two - l1 * pw(r2, 3) * t +
166 l2 * pw(r2, 3) * t + two * r1 * pw(r2, 3) * t + two * pw(r1, 3) * r2 * t +
167 three * r1 * r1 * r2 * r2 * t + two * l1 * r2 * r2 * SH - two * l2 * r2 * r2 * SH -
168 two * l1 * r1 * r2 * r2 * t - l1 * r1 * r1 * r2 * t + two * l2 * r1 * r2 * r2 * t +
169 l2 * r1 * r1 * r2 * t + two * l1 * r1 * r2 * SH - two * l2 * r1 * r2 * SH) /
171 q.q1_x = -P4 / (four * DEN1);
172 q.q1_c = -CN / (four * DEN1);
173 q.q2_a = -(pw(r1, 4) * t / two + pw(r2, 4) * t / two + l1 * pw(r1, 3) * t -
174 l2 * pw(r1, 3) * t + two * r1 * pw(r2, 3) * t + two * pw(r1, 3) * r2 * t +
175 three * r1 * r1 * r2 * r2 * t - two * l1 * r1 * r1 * SH + two * l2 * r1 * r1 * SH +
176 l1 * r1 * r2 * r2 * t + two * l1 * r1 * r1 * r2 * t - l2 * r1 * r2 * r2 * t -
177 two * l2 * r1 * r1 * r2 * t - two * l1 * r1 * r2 * SH + two * l2 * r1 * r2 * SH) /
179 q.q2_x = P4 / (four * DEN2);
180 q.q2_c = CN / (four * DEN2);
190M3ppSplitCoeffs<T> m3pp_split_coeffs_ag(
const T& l1,
const T& l2,
const T& r1,
const T& r2,
192 const T zero = num_traits<T>::from_int(0);
193 const T two = num_traits<T>::from_int(2);
194 const T three = num_traits<T>::from_int(3);
195 const T E = num_exp(T(-(r1 + r2) * t));
197 const T f1num = l1 * r2 *
198 (two * l2 * r1 - two * l1 * r1 + pw(r1, 3) * t + pw(r2, 3) * t +
199 two * l1 * r1 * r1 * t - two * l2 * r1 * r1 * t + three * r1 * r2 * r2 * t +
200 three * r1 * r1 * r2 * t + two * l1 * r1 * E - two * l2 * r1 * E +
201 two * l1 * r1 * r2 * t - two * l2 * r1 * r2 * t);
202 const T f1 = f1num / pw(T(r1 + r2), 4);
203 const T f2num = l2 * r1 *
204 (two * l1 * r2 - two * l2 * r2 + pw(r1, 3) * t + pw(r2, 3) * t -
205 two * l1 * r2 * r2 * t + two * l2 * r2 * r2 * t + three * r1 * r2 * r2 * t +
206 three * r1 * r1 * r2 * t - two * l1 * r2 * E + two * l2 * r2 * E -
207 two * l1 * r1 * r2 * t + two * l2 * r1 * r2 * t);
208 const T f2 = f2num / pw(T(r1 + r2), 4);
209 const T tmp = f1 * l2 * r1 - f2 * l1 * r2;
211 throw NumericError(
"m3pp2m_fitc_approx_ag: degenerate per-class split (f1 l2 r1 = f2 l1 r2)");
213 M3ppSplitCoeffs<T> q;
214 q.q1_a = -(f2 * (r1 + r2)) / tmp;
215 q.q1_x = (l2 * r1) / tmp;
217 q.q2_a = (f1 * (r1 + r2)) / tmp;
218 q.q2_x = -(l1 * r2) / tmp;
238std::vector<T> m3pp_split_solve(
const M3ppSplitCoeffs<T>& q,
const std::vector<T>& ai,
239 const std::vector<T>& target,
const T& a,
240 const std::vector<Bound<T>>& bounds,
const AugLagOptions<T>& opt,
241 T& objective, T& violation) {
242 const T zero = num_traits<T>::from_int(0);
243 const T one = num_traits<T>::from_int(1);
244 const std::size_t m = ai.size();
245 if (target.size() != m)
throw InputError(
"m3pp_split_solve: target length disagrees with ai");
246 for (std::size_t i = 0; i < m; ++i)
247 if (target[i] == zero)
248 throw InputError(
"m3pp_split_solve: a per-class target is zero, so the relative "
249 "objective of the reference is undefined");
250 if (!bounds.empty() && bounds.size() != m)
251 throw InputError(
"m3pp_split_solve: one bound per class is required");
253 const std::vector<T> tgt = target;
254 auto resid = [tgt, m, one](
const std::vector<T>& x) {
256 for (std::size_t i = 0; i < m; ++i) r[i] = x[i] / tgt[i] - one;
260 const std::vector<T> rates = ai;
261 const M3ppSplitCoeffs<T> qc = q;
262 const T mT = num_traits<T>::from_int(
long(m));
263 auto heq = [qc, rates, a, m, mT, one](
const std::vector<T>& x) {
264 T s = num_traits<T>::from_int(0);
265 for (std::size_t i = 0; i < m; ++i) s += x[i];
266 std::vector<T> hv(2);
267 hv[0] = qc.q1_a * a + qc.q1_x * s + mT * qc.q1_c - one;
268 hv[1] = qc.q2_a * a + qc.q2_x * s + mT * qc.q2_c - one;
271 const std::vector<Bound<T>> bnd = bounds;
272 auto gineq = [qc, rates, m, bnd](
const std::vector<T>& x) {
274 for (std::size_t i = 0; i < m; ++i) {
276 gv.push_back(T(-(qc.q1_a * rates[i] + qc.q1_x * x[i] + qc.q1_c)));
277 gv.push_back(T(-(qc.q2_a * rates[i] + qc.q2_x * x[i] + qc.q2_c)));
279 for (std::size_t i = 0; i < bnd.size(); ++i) {
280 if (bnd[i].has_lo) gv.push_back(T(bnd[i].lo - x[i]));
281 if (bnd[i].has_hi) gv.push_back(T(x[i] - bnd[i].hi));
287 std::vector<T> x0 = target;
288 const AugLagResult<T> sol =
auglag_ls(resid, m, heq, gineq, x0, opt);
289 objective = sol.fval;
290 violation = sol.violation;
305 if (q1.size() != q2.size())
throw InputError(
"m3pp2m_assemble: q1 and q2 differ in length");
309 for (std::size_t i = 0; i < q1.size(); ++i) {
311 Dc(0, 0) = q1[i] * base.
D1(0, 0);
312 Dc(1, 1) = q2[i] * base.
D1(1, 1);
322M3pp2mFitcApproxResult<T> m3pp2m_split_and_assemble(
const Map<T>& base,
323 const M3ppSplitCoeffs<T>& q,
324 const std::vector<T>& ai,
325 const std::vector<T>& target,
const T& a,
326 const std::vector<
Bound<T>>& bounds,
328 const std::size_t m = ai.size();
329 M3pp2mFitcApproxResult<T> res;
330 res.degenerate =
false;
335 const std::vector<T> x = m3pp_split_solve(q, ai, target, a, bounds,
opt, obj, viol);
337 std::vector<T> q1(m), q2(m);
338 for (std::size_t i = 0; i < m; ++i) {
339 q1[i] = q.q1_a * ai[i] + q.q1_x * x[i] + q.q1_c;
340 q2[i] = q.q2_a * ai[i] + q.q2_x * x[i] + q.q2_c;
343 res.class_objective = obj;
344 res.class_violation = viol;
351bool m3pp2m_trivial_split(
const Map<T>& base,
const std::vector<T>& ai,
const T& a,
352 M3pp2mFitcApproxResult<T>& res) {
353 const std::size_t m = ai.size();
354 if (base.D0.rows() == 1) {
356 res.degenerate =
true;
357 res.mmap.D0 = base.D0;
358 res.mmap.D1 = base.D1;
359 for (std::size_t i = 0; i < m; ++i) {
360 Matrix<T> Dc(1, 1, T(ai[i] / a * base.D1(0, 0)));
361 res.mmap.Dc.push_back(Dc);
363 res.class_objective = num_traits<T>::from_int(0);
364 res.class_violation = num_traits<T>::from_int(0);
369 res.mmap.D0 = base.D0;
370 res.mmap.D1 = base.D1;
371 res.mmap.Dc.push_back(base.D1);
372 res.class_objective = num_traits<T>::from_int(0);
373 res.class_violation = num_traits<T>::from_int(0);
396 const T& m3t2,
const T& t1,
const T& t2,
397 const std::vector<T>& ai,
const std::vector<T>& dvt3,
398 const T& t3,
const std::vector<
Bound<T>>& bounds,
401 "m3pp2m_fitc_approx requires transcendental arithmetic");
403 const std::size_t m = ai.size();
404 if (m == 0)
throw InputError(
"m3pp2m_fitc_approx: no classes");
406 for (std::size_t i = 0; i < m; ++i) asum += ai[i];
408 throw InputError(
"m3pp2m_fitc_approx: inconsistent per-class arrival rates");
415 if (fitdetail::m3pp2m_trivial_split(base.
map, ai, a, res))
return res;
417 const fitdetail::M3ppSplitCoeffs<T> q = fitdetail::m3pp_split_coeffs_dv(
418 base.
map.D1(0, 0), base.
map.D1(1, 1), base.
map.D0(0, 1), base.
map.D0(1, 0), t3);
420 fitdetail::m3pp2m_split_and_assemble(base.
map, q, ai, dvt3, a, bounds,
opt);
428 const T& m3t2,
const T& t1,
const T& t2,
429 const std::vector<T>& ai,
const std::vector<T>& dvt3,
433 return m3pp2m_fitc_approx(a, bt1, bt2, binf, m3t2, t1, t2, ai, dvt3, t3,
450 const std::vector<T>& ai,
451 const std::vector<T>& gt3,
const T& t3,
452 const std::vector<
Bound<T>>& bounds,
455 "m3pp2m_fitc_approx_ag_multiclass requires transcendental arithmetic");
457 const std::size_t m = ai.size();
458 if (m == 0)
throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: no classes");
461 for (std::size_t i = 0; i < m; ++i) asum += ai[i];
463 throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: inconsistent per-class arrival rates");
468 if (fitdetail::m3pp2m_trivial_split(mmpp, ai, a, res))
return res;
469 if (mmpp.
D0.rows() != 2)
470 throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: the underlying MAP must have order 2");
472 const fitdetail::M3ppSplitCoeffs<T> q = fitdetail::m3pp_split_coeffs_ag(
473 mmpp.
D1(0, 0), mmpp.
D1(1, 1), mmpp.
D0(0, 1), mmpp.
D0(1, 0), t3);
474 return fitdetail::m3pp2m_split_and_assemble(mmpp, q, ai, gt3, a, bounds,
opt);
480 const std::vector<T>& ai,
481 const std::vector<T>& gt3,
501 const T& binf,
const T& m3t2,
const T& t1,
502 const T& t2,
const std::vector<T>& ai,
503 const std::vector<T>& gt3,
const T& t3,
504 const std::vector<
Bound<T>>& bounds,
507 "m3pp2m_fitc_approx_ag requires transcendental arithmetic");
510 for (std::size_t i = 0; i < ai.size(); ++i) asum += ai[i];
512 throw InputError(
"m3pp2m_fitc_approx_ag: inconsistent per-class arrival rates");
524 const T& binf,
const T& m3t2,
const T& t1,
525 const T& t2,
const std::vector<T>& ai,
526 const std::vector<T>& gt3,
const T& t3) {
529 return m3pp2m_fitc_approx_ag(a, bt1, bt2, binf, m3t2, t1, t2, ai, gt3, t3,
Augmented Lagrangian method for equality- and inequality-constrained minimization,...
NumericError(const std::string &what)
The exception types the port throws.
Scalar helpers shared by the MAP/PH moment-matching headers.
Markovian arrival process descriptors: stationary vectors, rate, moments, autocorrelation and the ind...
Dense matrix and non-owning view.
Marked MAP (MMAP) algebra: per-class rates, class probabilities, superposition, normalization and sca...
MMPP(2) fitted to counting-process characteristics by optimization (matlab/lib/kpctoolbox/mmpp/mmpp2_...
M3pp2mFitcApproxResult< T > m3pp2m_fitc_approx_ag(const T &a, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2, const std::vector< T > &ai, const std::vector< T > >3, const T &t3, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
m3pp2m_fitc_approx_ag: fit the underlying MMPP(2) by optimization, then apply the 'ag' per-class spli...
bool mmap_isfeasible_tol(const Mmap< T > &m, const T &tol)
Feasibility of a marked MAP WITHIN A TOLERANCE, the semantics of matlab/lib/m3a/m3a/mmap/mmap_isfeasi...
M3pp2mFitcApproxResult< T > m3pp2m_fitc_approx_ag_multiclass(const Map< T > &mmpp, const std::vector< T > &ai, const std::vector< T > >3, const T &t3, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
m3pp2m_fitc_approx_ag_multiclass: split a GIVEN MMPP(2) into m classes on their variance-plus-covaria...
Mmap< T > m3pp2m_assemble(const Map< T > &base, const std::vector< T > &q1, const std::vector< T > &q2)
Assemble the M3PP from an underlying MAP and the per-phase marking probabilities.
Mmpp2FitcApproxResult< T > mmpp2_fitc_approx(const T &a, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2, const AugLagOptions< T > &opt)
Fit an MMPP(2) to counting characteristics.
M3pp2mFitcApproxResult< T > m3pp2m_fitc_approx(const T &a, const T &bt1, const T &bt2, const T &binf, const T &m3t2, const T &t1, const T &t2, const std::vector< T > &ai, const std::vector< T > &dvt3, const T &t3, const std::vector< Bound< T > > &bounds, const AugLagOptions< T > &opt)
m3pp2m_fitc_approx: fit the underlying MMPP(2) by optimization, then split the classes on their varia...
T map_lambda(const Map< T > &m)
Stationary arrival rate, lambda = pi D1 e.
AugLagOptions< T > auglag_defaults()
Defaults: rho0 = 10, growth 10, feasibility 1e-10, 50 outer iterations.
AugLagResult< T > auglag_ls(R r, std::size_t m, H h, G g, const std::vector< T > &x0, const AugLagOptions< T > &opt)
Augmented Lagrangian with a least-squares objective and levmar as the inner solver.
Number-type abstraction for the templated API port.
Tuning of the outer multiplier iteration.
Box constraint on one variable.
Result of the optimization-based M3PP(2, m) fits.
Mmap< T > mmap
the fitted M3PP(2, m)
T class_objective
sum_i (x_i/target_i - 1)^2, the reference's fit_error
bool feasible
mmap_isfeasible_tol of the result at 1e-8
T mmpp_objective
objective of the underlying MMPP(2) fit (zero when it was given)
bool degenerate
the underlying process was a Poisson process
T class_violation
worst constraint violation of the per-class QP
A MAP as the pair of matrices (D0, D1).
An MMAP: the underlying MAP plus the per-class arrival matrices.
std::vector< Matrix< T > > Dc
per-class matrices, sum_c Dc = D1
Result of mmpp2_fitc_approx.
Map< T > map
the fitted MMPP(2), rescaled to rate a
T objective
sum of squared relative errors at the optimum