5#ifndef LINE_API_MAM_APH2_ADJUST_OPT_H
6#define LINE_API_MAM_APH2_ADJUST_OPT_H
102bool aph2_moments_feasible(
const T& M1,
const T& M2,
const T& M3,
const T& tol) {
108 const T M1sq = M1 * M1;
109 const T scv = (M2 - M1sq) / M1sq;
110 if (scv < half * (one - tol))
return false;
112 const T d = one - scv;
113 const T lb = three * pw(M1, 3) * (three * scv - one + num_sqrt(two) * d * num_sqrt(d));
114 const T ub = six * pw(M1, 3) * scv;
115 return M3 >= lb * (one - tol) && M3 <= ub * (one + tol);
117 const T lb = three / two * pw(M1, 3) * (one + scv) * (one + scv);
118 return M3 >= lb * (one - tol);
140std::vector<T> aph2_moment_bounds_rows(
const T& M1,
const T& xM2,
const T& xM3) {
148 const T M1sq = M1 * M1;
149 const T scv = (xM2 - M1sq) / M1sq;
150 std::vector<T> c(3, zero);
153 const T d = one - scv;
154 const T lb = three * pw(M1, 3) * (three * scv - one + num_sqrt(two) * d * num_sqrt(d));
155 const T ub = six * pw(M1, 3) * scv;
159 const T lb = three / two * pw(M1, 3) * (one + scv) * (one + scv);
182struct Aph2Inversion {
190Aph2Inversion<T> aph2_invert(
const T& M1,
const T& xM2,
const T& xM3,
bool swapped,
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 six = num_traits<T>::from_int(6);
196 const T eight = num_traits<T>::from_int(8);
197 const T nine = num_traits<T>::from_int(9);
198 const T twelve = num_traits<T>::from_int(12);
201 r.tmp0 = eight * pw(M1, 3) * xM3 / three - three * M1 * M1 * xM2 * xM2 -
202 two * M1 * xM2 * xM3 + two * pw(xM2, 3) + xM3 * xM3 / nine;
203 const T root = r.tmp0 > zero ? num_sqrt(r.tmp0) : zero;
204 const T tmp1 = three * root;
205 const T tmp2 = xM3 - three * M1 * xM2;
206 T tmp3 = six * xM2 - twelve * M1 * M1;
207 if (
num_abs(tmp3) < degen) tmp3 = tmp3 < zero ? T(-degen) : degen;
209 r.l1 = (tmp2 + tmp1) / tmp3;
210 r.l2 = (tmp2 - tmp1) / tmp3;
212 r.l1 = (tmp2 - tmp1) / tmp3;
213 r.l2 = (tmp2 + tmp1) / tmp3;
218 r.p1 = (M1 - r.l1) / r.l2;
237 const T& feastol,
const T& degentol) {
239 "aph2_adjust_opt_param requires transcendental arithmetic");
246 if (M1 <= zero)
throw InputError(
"aph2_adjust_opt_param: non-positive first moment");
250 auto moments = [M1, two, six](
const std::vector<T>& x, T& xM2, T& xM3) {
253 const T l1 = M1 - l2 * r1;
254 xM2 = two * l1 * l1 + two * r1 * l1 * l2 + two * r1 * l2 * l2;
255 xM3 = six * fitdetail::pw(l1, 3) + six * r1 * l1 * l1 * l2 + six * r1 * l1 * l2 * l2 +
256 six * r1 * fitdetail::pw(l2, 3);
259 auto resid = [moments, M2, M3](
const std::vector<T>& x) {
262 moments(x, xM2, xM3);
270 auto g = [feastol, degentol, one, M1](
const std::vector<T>& x) {
271 std::vector<T> gv(4);
272 gv[0] = feastol - x[0];
273 gv[1] = degentol - x[1];
274 gv[2] = x[1] - (one - degentol);
275 gv[3] = x[0] * x[1] - M1 + feastol;
279 std::vector<T> x0(2);
289 const T d2 = M2 - r.
M2a;
290 const T d3 = M3 - r.
M3a;
291 r.
objective = sqrt(T(d2 * d2 + d3 * d3));
322 "aph2_adjust_opt_char requires transcendental arithmetic");
325 if (M1 <= zero)
throw InputError(
"aph2_adjust_opt_char: non-positive first moment");
327 auto resid = [M2, M3](
const std::vector<T>& x) {
335 bool have_best =
false;
337 for (
int branch = 0; branch < 2; ++branch) {
338 const bool swapped = branch == 1;
339 auto g = [M1, swapped, postol, degen](
const std::vector<T>& x) {
340 const fitdetail::Aph2Inversion<T> inv =
341 fitdetail::aph2_invert(M1, x[0], x[1], swapped, degen);
342 std::vector<T> gv(6);
344 gv[1] = -inv.l1 + postol;
345 gv[2] = -inv.l2 + postol;
349 const std::vector<T> th = fitdetail::aph2_moment_bounds_rows(M1, x[0], x[1]);
350 for (std::size_t k = 0; k < th.size(); ++k) gv.push_back(th[k]);
354 std::vector<T> x0(2);
365 const T d2 = cand.
M2a - M2;
366 const T d3 = cand.
M3a - M3;
367 cand.
objective = sqrt(T(d2 * d2 + d3 * d3));
372 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...
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