240 const std::vector<T>& weights,
int method,
241 int constraints,
const T& tol) {
243 "amap2_adjust_gamma requires transcendental arithmetic");
252 if (M1 <= zero)
throw InputError(
"amap2_adjust_gamma: non-positive first moment");
253 if (weights.size() != 3)
throw InputError(
"amap2_adjust_gamma: three weights are required");
254 if (constraints == 1)
256 "amap2_adjust_gamma: constraints = 1 uses a 0/1 feasibility indicator that only a "
257 "direct-search poll can exploit; not ported");
258 if (constraints != 2)
throw InputError(
"amap2_adjust_gamma: constraints must be 1 or 2");
261 if (method != 3 && (M2 == zero || M3 == zero || GAMMA == zero))
263 "amap2_adjust_gamma: methods 1, 2 and 4 minimize a RELATIVE deviation, which is "
264 "undefined when a target is zero; use method 3");
273 T lb = zero, ub = zero;
274 fitdetail::amap2_gamma_bounds(M1, r.
M2a, r.
M3a, tol, lb, ub);
275 r.
GAMMAa = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
276 }
else if (method == 1) {
278 const T w0 = weights[0], w1 = weights[1], w2 = weights[2];
279 auto f = [M2, M3, GAMMA, w0, w1, w2](
const std::vector<T>& x) {
280 const T a0 = (x[0] - M2) / M2 * w0;
281 const T a1 = (x[1] - M3) / M3 * w1;
282 const T a2 = (x[2] - GAMMA) / GAMMA * w2;
284 return sqrt(T(a0 * a0 + a1 * a1 + a2 * a2));
286 auto g = [M1](
const std::vector<T>& x) {
287 return fitdetail::amap2_feasibility(M1, x[0], x[1], x[2]);
295 std::vector<unsigned> lags(2);
298 const std::vector<T> acf =
map_acf(feas, lags);
299 std::vector<T> x0(3);
302 x0[2] = acf[1] / acf[0];
306 T lb3 = zero, ub3 = zero;
307 fitdetail::amap2_gamma_bounds(M1, ad3.
M2a, ad3.
M3a, tol, lb3, ub3);
308 std::vector<T> x1(3);
311 x1[2] = GAMMA < lb3 ? lb3 : (GAMMA > ub3 ? ub3 : GAMMA);
313 std::vector<Bound<T>> bnd(3);
316 bnd[2] =
bound_box(T(-one), T(one - tol));
324 const bool take1 = (f1 && !f0) || (f1 == f0 && s1.
fval < s0.
fval);
329 }
else if (method == 2) {
331 r.
M2a = M2 > threehalf * M1 * M1 ? M2 : T(threehalf * M1 * M1);
333 const T n2 = r.
M2a / (M1 * M1);
335 bool ub_finite =
true;
336 if (n2 >= threehalf && n2 < two) {
337 const T p2 = three * (n2 - two) / (three * n2) *
338 (-two * fitdetail::num_sqrt(three) /
342 const T inner = p2 * p2 + two * p2 * (n2 - two);
343 const T a2 = (n2 - two) /
344 (p2 * (one - n2) + (inner > zero ? fitdetail::num_sqrt(inner) : zero));
345 const T l2 = three * (a2 + one) / (a2 * p2 + one) -
347 (two + a2 * p2 * (two * a2 + two));
349 FM3 = (l2 + (u2 - l2) / two) * M1 * r.
M2a;
350 M3_LB = l2 * M1 * r.
M2a;
351 M3_UB = u2 * M1 * r.
M2a;
353 FM3 = threehalf * r.
M2a * r.
M2a / M1 + tol;
359 const T w1 = weights[1], w2 = weights[2];
360 auto f = [M3, GAMMA, w1, w2](
const std::vector<T>& x) {
361 const T a1 = (x[0] - M3) / M3 * w1;
362 const T a2 = (x[1] - GAMMA) / GAMMA * w2;
364 return sqrt(T(a1 * a1 + a2 * a2));
366 const T M2a_c = r.
M2a;
367 auto g = [M1, M2a_c](
const std::vector<T>& x) {
368 return fitdetail::amap2_feasibility(M1, M2a_c, x[0], x[1]);
371 std::vector<T> x0(2);
374 std::vector<Bound<T>> bnd(2);
376 bnd[1] =
bound_box(T(-one), T(one - tol));
383 }
else if (method == 4) {
385 const T M1sq = M1 * M1;
386 const T scv = (M2 - M1sq) / M1sq;
389 r.
M2a = threehalf * M1sq;
390 scva = (r.
M2a - M1sq) / M1sq;
398 const T d = one - scva;
399 M3_lb = three * fitdetail::pw(M1, 3) *
400 (three * scva - one + fitdetail::num_sqrt(two) * d * fitdetail::num_sqrt(d));
404 M3_lb = threehalf * fitdetail::pw(M1, 3) * (one + scva) * (one + scva);
409 if (ub_finite &&
num_abs(T(M3_lb - M3_ub)) < tol) {
410 r.
M3a = (M3_lb + M3_ub) / two;
413 const T w1 = weights[1], w2 = weights[2];
414 const T M2a_c = r.
M2a;
415 auto obj = [M1, M2a_c, M3, GAMMA, w1, w2, tol](
const std::vector<T>& x) {
417 fitdetail::amap2_gamma_bounds(M1, M2a_c, x[0], tol, lb, ub);
418 const T ga = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
421 return T(w1 * a1 * a1 + w2 * a2 * a2);
425 const T lo = M3_lb + tol;
426 std::vector<T> starts;
427 const unsigned nstart = 9;
428 for (
unsigned k = 0; k < nstart; ++k) {
432 starts.push_back(T(lo + frac * (M3_ub - lo)));
437 std::vector<Bound<T>> bnd(1);
447 for (std::size_t k = 0; k < starts.size(); ++k) {
448 std::vector<T> x0(1, starts[k]);
450 if (!have || s.
fval < bestf) {
457 T lb = zero, ub = zero;
458 fitdetail::amap2_gamma_bounds(M1, r.
M2a, r.
M3a, tol, lb, ub);
459 r.
GAMMAa = GAMMA < lb ? lb : (GAMMA > ub ? ub : GAMMA);
462 throw InputError(
"amap2_adjust_gamma: method must be 1, 2, 3 or 4");
466 if (M2 == zero || M3 == zero || GAMMA == zero) {
469 const T a0 = (r.
M2a - M2) / M2 * weights[0];
470 const T a1 = (r.
M3a - M3) / M3 * weights[1];
471 const T a2 = (r.
GAMMAa - GAMMA) / GAMMA * weights[2];
472 r.
objective = sqrt(T(a0 * a0 + a1 * a1 + a2 * a2));