5#ifndef LINE_API_MAM_M3PP2M_FITC_APPROX_H
6#define LINE_API_MAM_M3PP2M_FITC_APPROX_H
110struct M3ppSplitCoeffs {
126M3ppSplitCoeffs<T> m3pp_split_coeffs_dv(
const T& l1,
const T& l2,
const T& r1,
const T& r2,
132 const T SH = (one - num_exp(T(-(r1 + r2) * t))) / two;
134 const T BR = two * l1 * SH - two * l2 * SH - l1 * r1 * t - l1 * r2 * t + l2 * r1 * t +
136 const T DEN1 = l1 * r2 * (r1 + r2) * BR;
137 const T BR2 = l2 * l2 * r1 * r1 * t - two * l2 * l2 * r1 * SH - l1 * l2 * r1 * r1 * t +
138 l2 * l2 * r1 * r2 * t + two * l1 * l2 * r1 * SH - l1 * l2 * r1 * r2 * t;
139 const T DEN2 = (r1 + r2) * BR2;
142 four * r1 * pw(r2, 3) + pw(r2, 4);
143 const T CN = l1 * pw(r2, 4) * t + l2 * pw(r1, 4) * t + three * l1 * r1 * pw(r2, 3) * t +
144 l1 * pw(r1, 3) * r2 * t + l2 * r1 * pw(r2, 3) * t + three * l2 * pw(r1, 3) * r2 * t +
145 three * l1 * r1 * r1 * r2 * r2 * t + two * l1 * l1 * r1 * r2 * r2 * t +
146 two * l1 * l1 * r1 * r1 * r2 * t + three * l2 * r1 * r1 * r2 * r2 * t +
147 two * l2 * l2 * r1 * r2 * r2 * t + two * l2 * l2 * r1 * r1 * r2 * t -
148 four * l1 * l1 * r1 * r2 * SH - four * l2 * l2 * r1 * r2 * SH -
149 four * l1 * l2 * r1 * r2 * r2 * t - four * l1 * l2 * r1 * r1 * r2 * t +
152 M3ppSplitCoeffs<T> q;
153 q.q1_a = (pw(r1, 4) * t / two + pw(r2, 4) * t / two - l1 * pw(r2, 3) * t +
154 l2 * pw(r2, 3) * t + two * r1 * pw(r2, 3) * t + two * pw(r1, 3) * r2 * t +
155 three * r1 * r1 * r2 * r2 * t + two * l1 * r2 * r2 * SH - two * l2 * r2 * r2 * SH -
156 two * l1 * r1 * r2 * r2 * t - l1 * r1 * r1 * r2 * t + two * l2 * r1 * r2 * r2 * t +
157 l2 * r1 * r1 * r2 * t + two * l1 * r1 * r2 * SH - two * l2 * r1 * r2 * SH) /
159 q.q1_x = -P4 / (four * DEN1);
160 q.q1_c = -CN / (four * DEN1);
161 q.q2_a = -(pw(r1, 4) * t / two + pw(r2, 4) * t / two + l1 * pw(r1, 3) * t -
162 l2 * pw(r1, 3) * t + two * r1 * pw(r2, 3) * t + two * pw(r1, 3) * r2 * t +
163 three * r1 * r1 * r2 * r2 * t - two * l1 * r1 * r1 * SH + two * l2 * r1 * r1 * SH +
164 l1 * r1 * r2 * r2 * t + two * l1 * r1 * r1 * r2 * t - l2 * r1 * r2 * r2 * t -
165 two * l2 * r1 * r1 * r2 * t - two * l1 * r1 * r2 * SH + two * l2 * r1 * r2 * SH) /
167 q.q2_x = P4 / (four * DEN2);
168 q.q2_c = CN / (four * DEN2);
178M3ppSplitCoeffs<T> m3pp_split_coeffs_ag(
const T& l1,
const T& l2,
const T& r1,
const T& r2,
180 const T zero = num_traits<T>::from_int(0);
181 const T two = num_traits<T>::from_int(2);
182 const T three = num_traits<T>::from_int(3);
183 const T E = num_exp(T(-(r1 + r2) * t));
185 const T f1num = l1 * r2 *
186 (two * l2 * r1 - two * l1 * r1 + pw(r1, 3) * t + pw(r2, 3) * t +
187 two * l1 * r1 * r1 * t - two * l2 * r1 * r1 * t + three * r1 * r2 * r2 * t +
188 three * r1 * r1 * r2 * t + two * l1 * r1 * E - two * l2 * r1 * E +
189 two * l1 * r1 * r2 * t - two * l2 * r1 * r2 * t);
190 const T f1 = f1num / pw(T(r1 + r2), 4);
191 const T f2num = l2 * r1 *
192 (two * l1 * r2 - two * l2 * r2 + pw(r1, 3) * t + pw(r2, 3) * t -
193 two * l1 * r2 * r2 * t + two * l2 * r2 * r2 * t + three * r1 * r2 * r2 * t +
194 three * r1 * r1 * r2 * t - two * l1 * r2 * E + two * l2 * r2 * E -
195 two * l1 * r1 * r2 * t + two * l2 * r1 * r2 * t);
196 const T f2 = f2num / pw(T(r1 + r2), 4);
197 const T tmp = f1 * l2 * r1 - f2 * l1 * r2;
199 throw NumericError(ErrorKind{
"Degenerate"},
"m3pp2m_fitc_approx_ag: degenerate per-class split (f1 l2 r1 = f2 l1 r2)");
201 M3ppSplitCoeffs<T> q;
202 q.q1_a = -(f2 * (r1 + r2)) / tmp;
203 q.q1_x = (l2 * r1) / tmp;
205 q.q2_a = (f1 * (r1 + r2)) / tmp;
206 q.q2_x = -(l1 * r2) / tmp;
226std::vector<T> m3pp_split_solve(
const M3ppSplitCoeffs<T>& q,
const std::vector<T>& ai,
227 const std::vector<T>& target,
const T& a,
228 const std::vector<Bound<T>>& bounds,
const AugLagOptions<T>& opt,
229 T& objective, T& violation) {
230 const T zero = num_traits<T>::from_int(0);
231 const T one = num_traits<T>::from_int(1);
232 const std::size_t m = ai.size();
233 if (target.size() != m)
throw InputError(
"m3pp_split_solve: target length disagrees with ai");
234 for (std::size_t i = 0; i < m; ++i)
235 if (target[i] == zero)
236 throw InputError(
"m3pp_split_solve: a per-class target is zero, so the relative "
237 "objective of the reference is undefined");
238 if (!bounds.empty() && bounds.size() != m)
239 throw InputError(
"m3pp_split_solve: one bound per class is required");
241 const std::vector<T> tgt = target;
242 auto resid = [tgt, m, one](
const std::vector<T>& x) {
244 for (std::size_t i = 0; i < m; ++i) r[i] = x[i] / tgt[i] - one;
248 const std::vector<T> rates = ai;
249 const M3ppSplitCoeffs<T> qc = q;
250 const T mT = num_traits<T>::from_int(
long(m));
251 auto heq = [qc, rates, a, m, mT, one](
const std::vector<T>& x) {
252 T s = num_traits<T>::from_int(0);
253 for (std::size_t i = 0; i < m; ++i) s += x[i];
254 std::vector<T> hv(2);
255 hv[0] = qc.q1_a * a + qc.q1_x * s + mT * qc.q1_c - one;
256 hv[1] = qc.q2_a * a + qc.q2_x * s + mT * qc.q2_c - one;
259 const std::vector<Bound<T>> bnd = bounds;
260 auto gineq = [qc, rates, m, bnd](
const std::vector<T>& x) {
262 for (std::size_t i = 0; i < m; ++i) {
264 gv.push_back(T(-(qc.q1_a * rates[i] + qc.q1_x * x[i] + qc.q1_c)));
265 gv.push_back(T(-(qc.q2_a * rates[i] + qc.q2_x * x[i] + qc.q2_c)));
267 for (std::size_t i = 0; i < bnd.size(); ++i) {
268 if (bnd[i].has_lo) gv.push_back(T(bnd[i].lo - x[i]));
269 if (bnd[i].has_hi) gv.push_back(T(x[i] - bnd[i].hi));
275 std::vector<T> x0 = target;
276 const AugLagResult<T> sol =
auglag_ls(resid, m, heq, gineq, x0, opt);
277 objective = sol.fval;
278 violation = sol.violation;
293 if (q1.size() != q2.size())
throw InputError(
"m3pp2m_assemble: q1 and q2 differ in length");
297 for (std::size_t i = 0; i < q1.size(); ++i) {
299 Dc(0, 0) = q1[i] * base.
D1(0, 0);
300 Dc(1, 1) = q2[i] * base.
D1(1, 1);
310M3pp2mFitcApproxResult<T> m3pp2m_split_and_assemble(
const Map<T>& base,
311 const M3ppSplitCoeffs<T>& q,
312 const std::vector<T>& ai,
313 const std::vector<T>& target,
const T& a,
314 const std::vector<
Bound<T>>& bounds,
316 const std::size_t m = ai.size();
317 M3pp2mFitcApproxResult<T> res;
318 res.degenerate =
false;
323 const std::vector<T> x = m3pp_split_solve(q, ai, target, a, bounds,
opt, obj, viol);
325 std::vector<T> q1(m), q2(m);
326 for (std::size_t i = 0; i < m; ++i) {
327 q1[i] = q.q1_a * ai[i] + q.q1_x * x[i] + q.q1_c;
328 q2[i] = q.q2_a * ai[i] + q.q2_x * x[i] + q.q2_c;
331 res.class_objective = obj;
332 res.class_violation = viol;
339bool m3pp2m_trivial_split(
const Map<T>& base,
const std::vector<T>& ai,
const T& a,
340 M3pp2mFitcApproxResult<T>& res) {
341 const std::size_t m = ai.size();
342 if (base.D0.rows() == 1) {
344 res.degenerate =
true;
345 res.mmap.D0 = base.D0;
346 res.mmap.D1 = base.D1;
347 for (std::size_t i = 0; i < m; ++i) {
348 Matrix<T> Dc(1, 1, T(ai[i] / a * base.D1(0, 0)));
349 res.mmap.Dc.push_back(Dc);
351 res.class_objective = num_traits<T>::from_int(0);
352 res.class_violation = num_traits<T>::from_int(0);
357 res.mmap.D0 = base.D0;
358 res.mmap.D1 = base.D1;
359 res.mmap.Dc.push_back(base.D1);
360 res.class_objective = num_traits<T>::from_int(0);
361 res.class_violation = num_traits<T>::from_int(0);
384 const T& m3t2,
const T& t1,
const T& t2,
385 const std::vector<T>& ai,
const std::vector<T>& dvt3,
386 const T& t3,
const std::vector<
Bound<T>>& bounds,
389 "m3pp2m_fitc_approx requires transcendental arithmetic");
391 const std::size_t m = ai.size();
392 if (m == 0)
throw InputError(
"m3pp2m_fitc_approx: no classes");
394 for (std::size_t i = 0; i < m; ++i) asum += ai[i];
396 throw InputError(
"m3pp2m_fitc_approx: inconsistent per-class arrival rates");
403 if (fitdetail::m3pp2m_trivial_split(base.
map, ai, a, res))
return res;
405 const fitdetail::M3ppSplitCoeffs<T> q = fitdetail::m3pp_split_coeffs_dv(
406 base.
map.D1(0, 0), base.
map.D1(1, 1), base.
map.D0(0, 1), base.
map.D0(1, 0), t3);
408 fitdetail::m3pp2m_split_and_assemble(base.
map, q, ai, dvt3, a, bounds,
opt);
416 const T& m3t2,
const T& t1,
const T& t2,
417 const std::vector<T>& ai,
const std::vector<T>& dvt3,
421 return m3pp2m_fitc_approx(a, bt1, bt2, binf, m3t2, t1, t2, ai, dvt3, t3,
438 const std::vector<T>& ai,
439 const std::vector<T>& gt3,
const T& t3,
440 const std::vector<
Bound<T>>& bounds,
443 "m3pp2m_fitc_approx_ag_multiclass requires transcendental arithmetic");
445 const std::size_t m = ai.size();
446 if (m == 0)
throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: no classes");
449 for (std::size_t i = 0; i < m; ++i) asum += ai[i];
451 throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: inconsistent per-class arrival rates");
456 if (fitdetail::m3pp2m_trivial_split(mmpp, ai, a, res))
return res;
457 if (mmpp.
D0.rows() != 2)
458 throw InputError(
"m3pp2m_fitc_approx_ag_multiclass: the underlying MAP must have order 2");
460 const fitdetail::M3ppSplitCoeffs<T> q = fitdetail::m3pp_split_coeffs_ag(
461 mmpp.
D1(0, 0), mmpp.
D1(1, 1), mmpp.
D0(0, 1), mmpp.
D0(1, 0), t3);
462 return fitdetail::m3pp2m_split_and_assemble(mmpp, q, ai, gt3, a, bounds,
opt);
468 const std::vector<T>& ai,
469 const std::vector<T>& gt3,
489 const T& binf,
const T& m3t2,
const T& t1,
490 const T& t2,
const std::vector<T>& ai,
491 const std::vector<T>& gt3,
const T& t3,
492 const std::vector<
Bound<T>>& bounds,
495 "m3pp2m_fitc_approx_ag requires transcendental arithmetic");
498 for (std::size_t i = 0; i < ai.size(); ++i) asum += ai[i];
500 throw InputError(
"m3pp2m_fitc_approx_ag: inconsistent per-class arrival rates");
512 const T& binf,
const T& m3t2,
const T& t1,
513 const T& t2,
const std::vector<T>& ai,
514 const std::vector<T>& gt3,
const T& t3) {
517 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.
Conservation laws of a layered queueing network, enumerated from its structure.
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