5#ifndef LINE_API_MAM_APH2_ADJUST_OPT_H
6#define LINE_API_MAM_APH2_ADJUST_OPT_H
97bool aph2_moments_feasible(
const T& M1,
const T& M2,
const T& M3,
const T& tol) {
103 const T M1sq = M1 * M1;
104 const T scv = (M2 - M1sq) / M1sq;
105 if (scv < half * (one - tol))
return false;
107 const T d = one - scv;
108 const T lb = three * pw(M1, 3) * (three * scv - one + num_sqrt(two) * d * num_sqrt(d));
109 const T ub = six * pw(M1, 3) * scv;
110 return M3 >= lb * (one - tol) && M3 <= ub * (one + tol);
112 const T lb = three / two * pw(M1, 3) * (one + scv) * (one + scv);
113 return M3 >= lb * (one - tol);
135std::vector<T> aph2_moment_bounds_rows(
const T& M1,
const T& xM2,
const T& xM3) {
143 const T M1sq = M1 * M1;
144 const T scv = (xM2 - M1sq) / M1sq;
145 std::vector<T> c(3, zero);
148 const T d = one - scv;
149 const T lb = three * pw(M1, 3) * (three * scv - one + num_sqrt(two) * d * num_sqrt(d));
150 const T ub = six * pw(M1, 3) * scv;
154 const T lb = three / two * pw(M1, 3) * (one + scv) * (one + scv);
177struct Aph2Inversion {
185Aph2Inversion<T> aph2_invert(
const T& M1,
const T& xM2,
const T& xM3,
bool swapped,
187 const T zero = num_traits<T>::from_int(0);
188 const T two = num_traits<T>::from_int(2);
189 const T three = num_traits<T>::from_int(3);
190 const T six = num_traits<T>::from_int(6);
191 const T eight = num_traits<T>::from_int(8);
192 const T nine = num_traits<T>::from_int(9);
193 const T twelve = num_traits<T>::from_int(12);
196 r.tmp0 = eight * pw(M1, 3) * xM3 / three - three * M1 * M1 * xM2 * xM2 -
197 two * M1 * xM2 * xM3 + two * pw(xM2, 3) + xM3 * xM3 / nine;
198 const T root = r.tmp0 > zero ? num_sqrt(r.tmp0) : zero;
199 const T tmp1 = three * root;
200 const T tmp2 = xM3 - three * M1 * xM2;
201 T tmp3 = six * xM2 - twelve * M1 * M1;
202 if (
num_abs(tmp3) < degen) tmp3 = tmp3 < zero ? T(-degen) : degen;
204 r.l1 = (tmp2 + tmp1) / tmp3;
205 r.l2 = (tmp2 - tmp1) / tmp3;
207 r.l1 = (tmp2 - tmp1) / tmp3;
208 r.l2 = (tmp2 + tmp1) / tmp3;
213 r.p1 = (M1 - r.l1) / r.l2;
232 const T& feastol,
const T& degentol) {
234 "aph2_adjust_opt_param requires transcendental arithmetic");
241 if (M1 <= zero)
throw InputError(
"aph2_adjust_opt_param: non-positive first moment");
245 auto moments = [M1, two, six](
const std::vector<T>& x, T& xM2, T& xM3) {
248 const T l1 = M1 - l2 * r1;
249 xM2 = two * l1 * l1 + two * r1 * l1 * l2 + two * r1 * l2 * l2;
250 xM3 = six * fitdetail::pw(l1, 3) + six * r1 * l1 * l1 * l2 + six * r1 * l1 * l2 * l2 +
251 six * r1 * fitdetail::pw(l2, 3);
254 auto resid = [moments, M2, M3](
const std::vector<T>& x) {
257 moments(x, xM2, xM3);
265 auto g = [feastol, degentol, one, M1](
const std::vector<T>& x) {
266 std::vector<T> gv(4);
267 gv[0] = feastol - x[0];
268 gv[1] = degentol - x[1];
269 gv[2] = x[1] - (one - degentol);
270 gv[3] = x[0] * x[1] - M1 + feastol;
274 std::vector<T> x0(2);
284 const T d2 = M2 - r.
M2a;
285 const T d3 = M3 - r.
M3a;
286 r.
objective = sqrt(T(d2 * d2 + d3 * d3));
317 "aph2_adjust_opt_char requires transcendental arithmetic");
320 if (M1 <= zero)
throw InputError(
"aph2_adjust_opt_char: non-positive first moment");
322 auto resid = [M2, M3](
const std::vector<T>& x) {
330 bool have_best =
false;
332 for (
int branch = 0; branch < 2; ++branch) {
333 const bool swapped = branch == 1;
334 auto g = [M1, swapped, postol, degen](
const std::vector<T>& x) {
335 const fitdetail::Aph2Inversion<T> inv =
336 fitdetail::aph2_invert(M1, x[0], x[1], swapped, degen);
337 std::vector<T> gv(6);
339 gv[1] = -inv.l1 + postol;
340 gv[2] = -inv.l2 + postol;
344 const std::vector<T> th = fitdetail::aph2_moment_bounds_rows(M1, x[0], x[1]);
345 for (std::size_t k = 0; k < th.size(); ++k) gv.push_back(th[k]);
349 std::vector<T> x0(2);
360 const T d2 = cand.
M2a - M2;
361 const T d3 = cand.
M3a - M3;
362 cand.
objective = sqrt(T(d2 * d2 + d3 * d3));
367 if (!cand.
converged && have_best)
continue;
Augmented Lagrangian method for equality- and inequality-constrained minimization,...
The exception types the port throws.
Scalar helpers shared by the MAP/PH moment-matching headers.
Aph2AdjustOptResult< T > aph2_adjust_opt_param(const T &M1, const T &M2, const T &M3, const T &feastol, const T °entol)
aph2_adjust, method 'opt_param': adjust (M2, M3) by searching the APH(2) parameter space with M1 matc...
Aph2AdjustOptResult< T > aph2_adjust_opt_char(const T &M1, const T &M2, const T &M3, const T &postol, const T °en)
aph2_adjust, method 'opt_char': adjust (M2, M3) by searching the moment space subject to APH(2) inver...
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.
Outcome of a constrained solve.
std::vector< T > x
best point found
T violation
max(|h_i|, max(0, g_j)) at x
A constraint map that returns no constraints; the default for h or g.
Result of an optimization-based APH(2) moment adjustment.
T M2a
adjusted second moment
T violation
worst constraint violation at the returned point
bool converged
the constrained solve reached feasibility within its caps
T objective
||(M2a, M3a) - (M2, M3)||, the reference's objective
T M3a
adjusted third moment