253 const std::vector<T>& weights,
int method,
254 int constraints,
const T& tol) {
256 "amap2_adjust_gamma requires transcendental arithmetic");
265 if (M1 <= zero)
throw InputError(
"amap2_adjust_gamma: non-positive first moment");
266 if (weights.size() != 3)
throw InputError(
"amap2_adjust_gamma: three weights are required");
267 if (constraints == 1)
269 "amap2_adjust_gamma: constraints = 1 uses a 0/1 feasibility indicator that only a "
270 "direct-search poll can exploit; not ported");
271 if (constraints != 2)
throw InputError(
"amap2_adjust_gamma: constraints must be 1 or 2");
274 if (method != 3 && (M2 == zero || M3 == zero || GAMMA == zero))
276 "amap2_adjust_gamma: methods 1, 2 and 4 minimize a RELATIVE deviation, which is "
277 "undefined when a target is zero; use method 3");
286 T lb = zero, ub = zero;
287 fitdetail::amap2_gamma_bounds(M1, r.
M2a, r.
M3a, tol, lb, ub);
288 r.
GAMMAa = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
289 }
else if (method == 1) {
291 const T w0 = weights[0], w1 = weights[1], w2 = weights[2];
292 auto f = [M2, M3, GAMMA, w0, w1, w2](
const std::vector<T>& x) {
293 const T a0 = (x[0] - M2) / M2 * w0;
294 const T a1 = (x[1] - M3) / M3 * w1;
295 const T a2 = (x[2] - GAMMA) / GAMMA * w2;
297 return sqrt(T(a0 * a0 + a1 * a1 + a2 * a2));
299 auto g = [M1](
const std::vector<T>& x) {
300 return fitdetail::amap2_feasibility(M1, x[0], x[1], x[2]);
308 std::vector<unsigned> lags(2);
311 const std::vector<T> acf =
map_acf(feas, lags);
312 std::vector<T> x0(3);
315 x0[2] = acf[1] / acf[0];
319 T lb3 = zero, ub3 = zero;
320 fitdetail::amap2_gamma_bounds(M1, ad3.
M2a, ad3.
M3a, tol, lb3, ub3);
321 std::vector<T> x1(3);
324 x1[2] = GAMMA < lb3 ? lb3 : (GAMMA > ub3 ? ub3 : GAMMA);
326 std::vector<Bound<T>> bnd(3);
329 bnd[2] =
bound_box(T(-one), T(one - tol));
337 const bool take1 = (f1 && !f0) || (f1 == f0 && s1.
fval < s0.
fval);
342 }
else if (method == 2) {
344 r.
M2a = M2 > threehalf * M1 * M1 ? M2 : T(threehalf * M1 * M1);
346 const T n2 = r.
M2a / (M1 * M1);
348 bool ub_finite =
true;
349 if (n2 >= threehalf && n2 < two) {
350 const T p2 = three * (n2 - two) / (three * n2) *
351 (-two * fitdetail::num_sqrt(three) /
355 const T inner = p2 * p2 + two * p2 * (n2 - two);
356 const T a2 = (n2 - two) /
357 (p2 * (one - n2) + (inner > zero ? fitdetail::num_sqrt(inner) : zero));
358 const T l2 = three * (a2 + one) / (a2 * p2 + one) -
360 (two + a2 * p2 * (two * a2 + two));
362 FM3 = (l2 + (u2 - l2) / two) * M1 * r.
M2a;
363 M3_LB = l2 * M1 * r.
M2a;
364 M3_UB = u2 * M1 * r.
M2a;
366 FM3 = threehalf * r.
M2a * r.
M2a / M1 + tol;
372 const T w1 = weights[1], w2 = weights[2];
373 auto f = [M3, GAMMA, w1, w2](
const std::vector<T>& x) {
374 const T a1 = (x[0] - M3) / M3 * w1;
375 const T a2 = (x[1] - GAMMA) / GAMMA * w2;
377 return sqrt(T(a1 * a1 + a2 * a2));
379 const T M2a_c = r.
M2a;
380 auto g = [M1, M2a_c](
const std::vector<T>& x) {
381 return fitdetail::amap2_feasibility(M1, M2a_c, x[0], x[1]);
384 std::vector<T> x0(2);
387 std::vector<Bound<T>> bnd(2);
389 bnd[1] =
bound_box(T(-one), T(one - tol));
396 }
else if (method == 4) {
398 const T M1sq = M1 * M1;
399 const T scv = (M2 - M1sq) / M1sq;
402 r.
M2a = threehalf * M1sq;
403 scva = (r.
M2a - M1sq) / M1sq;
411 const T d = one - scva;
412 M3_lb = three * fitdetail::pw(M1, 3) *
413 (three * scva - one + fitdetail::num_sqrt(two) * d * fitdetail::num_sqrt(d));
417 M3_lb = threehalf * fitdetail::pw(M1, 3) * (one + scva) * (one + scva);
422 if (ub_finite &&
num_abs(T(M3_lb - M3_ub)) < tol) {
423 r.
M3a = (M3_lb + M3_ub) / two;
426 const T w1 = weights[1], w2 = weights[2];
427 const T M2a_c = r.
M2a;
428 auto obj = [M1, M2a_c, M3, GAMMA, w1, w2, tol](
const std::vector<T>& x) {
430 fitdetail::amap2_gamma_bounds(M1, M2a_c, x[0], tol, lb, ub);
431 const T ga = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
434 return T(w1 * a1 * a1 + w2 * a2 * a2);
438 const T lo = M3_lb + tol;
439 std::vector<T> starts;
440 const unsigned nstart = 9;
441 for (
unsigned k = 0; k < nstart; ++k) {
445 starts.push_back(T(lo + frac * (M3_ub - lo)));
450 std::vector<Bound<T>> bnd(1);
460 for (std::size_t k = 0; k < starts.size(); ++k) {
461 std::vector<T> x0(1, starts[k]);
463 if (!have || s.
fval < bestf) {
470 T lb = zero, ub = zero;
471 fitdetail::amap2_gamma_bounds(M1, r.
M2a, r.
M3a, tol, lb, ub);
472 r.
GAMMAa = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
475 throw InputError(
"amap2_adjust_gamma: method must be 1, 2, 3 or 4");
479 if (M2 == zero || M3 == zero || GAMMA == zero) {
482 const T a0 = (r.
M2a - M2) / M2 * weights[0];
483 const T a1 = (r.
M3a - M3) / M3 * weights[1];
484 const T a2 = (r.
GAMMAa - GAMMA) / GAMMA * weights[2];
485 r.
objective = sqrt(T(a0 * a0 + a1 * a1 + a2 * a2));