ScalingRootFinder Class Reference#

DiFfRG: DiFfRG::ScalingRootFinder Class Reference
DiFfRG
Discretization Framework for functional Renormalization Group flows

Bracketed root find accelerated by the critical scaling of the observable. More...

#include <root_finding.hh>

Classes

struct  Counts
 

Public Types

enum class  Acceptance { AtTarget , BelowTarget }
 What counts as an answer. More...
 

Public Member Functions

 ScalingRootFinder (FUN f, const double target, const double rel_tol=1e-3, const uint max_iter=40)
 
 ScalingRootFinder (FUN_NO_RESIDUAL f, const double target, const double rel_tol=1e-3, const uint max_iter=40)
 
double search ()
 
Bracket

The bounds are hypotheses by default: if they turn out not to straddle, the search widens them geometrically instead of throwing, which is what makes one set of bounds usable across models whose critical points differ by orders of magnitude.

void set_bounds (const double x_lo, const double x_hi)
 
void set_bounds_are_hypotheses (const bool v)
 
void set_expansion_factor (const double rho)
 
void set_expansion_max_iter (const uint n)
 
Stopping
void set_rel_tol (const double v)
 
void set_one_sided (const bool v)
 
void set_acceptance (const Acceptance a)
 
void set_aim_fraction (const double v)
 
void set_x_rel_floor (const double v)
 Bracket width, relative to the magnitude of the bounds, below which the search gives up.
 
void set_max_iter (const uint v)
 
Model trust windows

The power law is asymptotic. Fitting points from outside its window does not degrade gracefully – it returns a confident, badly wrong critical point that sits inside the bracket, where the containment safeguard cannot catch it. These windows are load-bearing.

void set_obs_window (const double v)
 Fit only points with obs <= window * target. Ignored when target == 0.
 
void set_residual_window (const double v)
 
void set_exponent_bounds (const double lo, const double hi)
 
void set_theta_bounds (const double lo, const double hi)
 
void set_endpoint_standoff (const double v)
 Fraction of the bracket width kept clear of either endpoint when clamping a proposal.
 
void set_approach_factor (const double v)
 Fraction of the remaining distance to the critical point kept per approach step.
 
void seed_exponent (const double beta)
 
Results
double get_obs () const
 
double get_x_critical () const
 
double get_exponent () const
 
double get_theta () const
 
bool have_model () const
 
double get_x_extrapolated () const
 Model extrapolation of the target point. NaN when no model was ever trusted.
 
bool converged () const
 
uint get_iter () const
 
double bracket_width () const
 Live bracket width; infinite until both sides are known.
 
const std::vector< std::pair< double, double > > & successes () const
 
const std::vector< std::pair< double, double > > & failures () const
 
Counts get_counts () const
 

Protected Types

using FUN = std::function<bool(const double, double &, double &)>
 
using FUN_NO_RESIDUAL = std::function<bool(const double, double &)>
 Compatibility shape matching BisectionRootFinderTarget. Disables the divergent-branch model.
 

Protected Member Functions

double effective_target () const
 
double extrapolate (const double x_c) const
 x at which the model predicts obs == effective_target(), given a critical point.
 
void refit ()
 
void fit_convergent ()
 Refit from the three convergent points closest to criticality (smallest obs).
 
void fit_divergent ()
 Refit from the three divergent points closest to criticality (largest residual).
 
double propose ()
 Propose the next x.
 
void record (double x, bool ok, double obs, double residual)
 Record a probe outcome and update the bracket.
 

Static Protected Member Functions

static std::array< std::size_t, 3 > select_triple (const std::size_t)
 The three candidates closest to criticality, out of n sorted by distance to it.
 

Protected Attributes

FUN f
 
double target
 
double rel_tol
 
uint max_iter
 
double x_lo_init = NAN
 
double x_hi_init = NAN
 
bool bounds_are_hypotheses = true
 
double expansion_factor = 2.
 
uint expansion_max_iter = 24
 
bool one_sided = true
 
Acceptance acceptance = Acceptance::AtTarget
 
double aim_fraction = 0.5
 
bool answer_found = false
 
double x_rel_floor = 1e-13
 
double obs_window = 20.
 
double residual_window = 0.
 
double beta_min = 0.02
 
double beta_max = 5.
 
double theta_min = 0.5
 
double theta_max = 8.
 
double endpoint_standoff = 0.02
 
double approach_factor = 0.1
 
double seeded_exponent = NAN
 
double x_lo_soft = -std::numeric_limits<double>::infinity()
 
double x_lo_hard = -std::numeric_limits<double>::infinity()
 
double x_hi = std::numeric_limits<double>::infinity()
 
std::vector< std::pair< double, double > > S
 (x, obs) for every finite evaluation
 
std::vector< std::pair< double, double > > F
 (x, residual) for every informative failure
 
bool model_valid = false
 
double model_x_c = NAN
 
double model_beta = NAN
 
double model_log_C = NAN
 
double model_theta = NAN
 
double model_x_c_prev = NAN
 
bool divergent_valid = false
 
double divergent_x_c = NAN
 
double divergent_shift = NAN
 
double best_x = NAN
 
double best_obs = NAN
 
bool have_success = false
 
bool m_converged = false
 
uint iter = 0
 
Counts counts
 
double w_prev = std::numeric_limits<double>::infinity()
 
double w_prevprev = std::numeric_limits<double>::infinity()
 
bool probed_hi_init = false
 
bool probed_lo_init = false
 
uint expansions = 0
 
double w_init = NAN
 

Detailed Description

Bracketed root find accelerated by the critical scaling of the observable.

Solves obs(x) == target where obs is smooth and monotone on the convergent side of a critical point x_c < x, obeying obs = C (x - x_c)^beta, and where probes below x_c fail but expose a residual that grows as x_c is approached, r(x) = a - ln(x_c - x)/theta. Neither exponent is assumed; both are fitted from three points, and the same solve serves both branches (the divergent one via x -> -x, y -> exp(-r), which is why only the residual differences ever enter and no exponentials are formed).

Every model-based proposal is bracket-safeguarded Brent-style, so a wrong model costs at most a factor two over plain bisection and can never move the answer.

The callback reports three outcomes, not two:

  • returns true and writes a finite obs: a usable evaluation. Whether it lies above or below the target is the finder's business, not the callback's.
  • returns false and writes a finite residual: the evaluation ran away; the residual says how far it got.
  • returns false and writes nothing: it failed some other way and carries no information beyond its own x. Both obs and residual are NaN-initialised before every call, so "wrote nothing" needs no separate signal.
[&](const double x, double &obs, double &residual) -> bool {
return run_at(x, obs, residual);
},
zc_target, 1e-3, 40);
search.set_bounds(lower, upper); // hypotheses; expanded if they do not straddle
search.set_residual_window(0.4 * final_time);
const double x = search.search();
Bracketed root find accelerated by the critical scaling of the observable.
Definition root_finding.hh:477
void set_bounds(const double x_lo, const double x_hi)
Definition root_finding.hh:513
double search()
Definition root_finding.hh:978

Member Typedef Documentation

◆ FUN

using DiFfRG::ScalingRootFinder::FUN = std::function<bool(const double, double &, double &)>
protected

◆ FUN_NO_RESIDUAL

using DiFfRG::ScalingRootFinder::FUN_NO_RESIDUAL = std::function<bool(const double, double &)>
protected

Compatibility shape matching BisectionRootFinderTarget. Disables the divergent-branch model.

Member Enumeration Documentation

◆ Acceptance

What counts as an answer.

AtTarget converges obs onto the target to within rel_tol. BelowTarget accepts the first evaluation that lands anywhere strictly between the critical point and the target crossing, which is a far easier thing to hit: on a cold Yang-Mills tune that interval is ~600x wider in the search variable than the AtTarget window, i.e. about nine bisections cheaper, and it lets a merely decent fit succeed on its first attempt instead of being refined until it is accurate to rel_tol.

Enumerator
AtTarget 
BelowTarget 

Constructor & Destructor Documentation

◆ ScalingRootFinder() [1/2]

DiFfRG::ScalingRootFinder::ScalingRootFinder ( FUN f,
const double target,
const double rel_tol = 1e-3,
const uint max_iter = 40 )
inline

◆ ScalingRootFinder() [2/2]

DiFfRG::ScalingRootFinder::ScalingRootFinder ( FUN_NO_RESIDUAL f,
const double target,
const double rel_tol = 1e-3,
const uint max_iter = 40 )
inline

Member Function Documentation

◆ bracket_width()

double DiFfRG::ScalingRootFinder::bracket_width ( ) const
inline

Live bracket width; infinite until both sides are known.

◆ converged()

bool DiFfRG::ScalingRootFinder::converged ( ) const
inline

◆ effective_target()

double DiFfRG::ScalingRootFinder::effective_target ( ) const
inlineprotected

The value actually aimed at. With one-sided acceptance the admissible window is [target, target(1+rel_tol)]; aiming at its centre rather than its lower edge keeps rounding in the extrapolation from landing just below and costing an extra evaluation.

◆ extrapolate()

double DiFfRG::ScalingRootFinder::extrapolate ( const double x_c) const
inlineprotected

x at which the model predicts obs == effective_target(), given a critical point.

◆ failures()

const std::vector< std::pair< double, double > > & DiFfRG::ScalingRootFinder::failures ( ) const
inline

◆ fit_convergent()

void DiFfRG::ScalingRootFinder::fit_convergent ( )
inlineprotected

Refit from the three convergent points closest to criticality (smallest obs).

◆ fit_divergent()

void DiFfRG::ScalingRootFinder::fit_divergent ( )
inlineprotected

Refit from the three divergent points closest to criticality (largest residual).

◆ get_counts()

Counts DiFfRG::ScalingRootFinder::get_counts ( ) const
inline

◆ get_exponent()

double DiFfRG::ScalingRootFinder::get_exponent ( ) const
inline

◆ get_iter()

uint DiFfRG::ScalingRootFinder::get_iter ( ) const
inline

◆ get_obs()

double DiFfRG::ScalingRootFinder::get_obs ( ) const
inline

◆ get_theta()

double DiFfRG::ScalingRootFinder::get_theta ( ) const
inline

◆ get_x_critical()

double DiFfRG::ScalingRootFinder::get_x_critical ( ) const
inline

Best available critical point: the convergent fit when it is trusted, otherwise the divergent one, which is usable much further from criticality.

◆ get_x_extrapolated()

double DiFfRG::ScalingRootFinder::get_x_extrapolated ( ) const
inline

Model extrapolation of the target point. NaN when no model was ever trusted.

◆ have_model()

bool DiFfRG::ScalingRootFinder::have_model ( ) const
inline

◆ propose()

double DiFfRG::ScalingRootFinder::propose ( )
inlineprotected

Propose the next x.

◆ record()

void DiFfRG::ScalingRootFinder::record ( double x,
bool ok,
double obs,
double residual )
inlineprotected

Record a probe outcome and update the bracket.

◆ refit()

void DiFfRG::ScalingRootFinder::refit ( )
inlineprotected

Refit both branches. Called exactly once per evaluation, so that the consecutive-fit agreement test sees successive iterations rather than successive calls.

◆ search()

double DiFfRG::ScalingRootFinder::search ( )
inline

◆ seed_exponent()

void DiFfRG::ScalingRootFinder::seed_exponent ( const double beta)
inline

Seed the exponent from a nearby earlier search (another simplex step, a coarser fidelity). Exponents are far more portable than amplitudes; do not seed the latter.

◆ select_triple()

static std::array< std::size_t, 3 > DiFfRG::ScalingRootFinder::select_triple ( const std::size_t )
inlinestaticprotected

The three candidates closest to criticality, out of n sorted by distance to it.

Spreading the triple across the whole admissible range is better conditioned in principle – a bisecting search leaves the closest points tightly clustered – but measures worse: the far points are not asymptotic enough, the fit is rejected outright more often, and a cold SP tune stopped converging inside its budget. Both laws are asymptotic, so the fit stays in the asymptote.

◆ set_acceptance()

void DiFfRG::ScalingRootFinder::set_acceptance ( const Acceptance a)
inline

◆ set_aim_fraction()

void DiFfRG::ScalingRootFinder::set_aim_fraction ( const double v)
inline

Where inside (0, target) to aim in BelowTarget mode, as a fraction of the target. Aiming at the midpoint rather than just under the crossing leaves room for the fit to be wrong in either direction without either overshooting into the divergent region or missing.

◆ set_approach_factor()

void DiFfRG::ScalingRootFinder::set_approach_factor ( const double v)
inline

Fraction of the remaining distance to the critical point kept per approach step.

◆ set_bounds()

void DiFfRG::ScalingRootFinder::set_bounds ( const double x_lo,
const double x_hi )
inline

◆ set_bounds_are_hypotheses()

void DiFfRG::ScalingRootFinder::set_bounds_are_hypotheses ( const bool v)
inline

◆ set_endpoint_standoff()

void DiFfRG::ScalingRootFinder::set_endpoint_standoff ( const double v)
inline

Fraction of the bracket width kept clear of either endpoint when clamping a proposal.

◆ set_expansion_factor()

void DiFfRG::ScalingRootFinder::set_expansion_factor ( const double rho)
inline

◆ set_expansion_max_iter()

void DiFfRG::ScalingRootFinder::set_expansion_max_iter ( const uint n)
inline

◆ set_exponent_bounds()

void DiFfRG::ScalingRootFinder::set_exponent_bounds ( const double lo,
const double hi )
inline

◆ set_max_iter()

void DiFfRG::ScalingRootFinder::set_max_iter ( const uint v)
inline

◆ set_obs_window()

void DiFfRG::ScalingRootFinder::set_obs_window ( const double v)
inline

Fit only points with obs <= window * target. Ignored when target == 0.

◆ set_one_sided()

void DiFfRG::ScalingRootFinder::set_one_sided ( const bool v)
inline

Accept only probes at or above the target. Keeps the answer on the safe side of the critical point at a cost of at most one extra evaluation. AtTarget mode only.

◆ set_rel_tol()

void DiFfRG::ScalingRootFinder::set_rel_tol ( const double v)
inline

◆ set_residual_window()

void DiFfRG::ScalingRootFinder::set_residual_window ( const double v)
inline

Fit only failures whose residual is at least this large. Defaults to 0 (fit any three), because only the caller knows the residual's scale.

◆ set_theta_bounds()

void DiFfRG::ScalingRootFinder::set_theta_bounds ( const double lo,
const double hi )
inline

Bounds on the divergent-branch exponent. theta is an inverse unstable RG eigenvalue and sits near the tuned parameter's mass dimension – 2 for a mass squared, measured 1.92 on a cold Yang-Mills tune – so it is far more tightly constrained a priori than beta.

◆ set_x_rel_floor()

void DiFfRG::ScalingRootFinder::set_x_rel_floor ( const double v)
inline

Bracket width, relative to the magnitude of the bounds, below which the search gives up.

◆ successes()

const std::vector< std::pair< double, double > > & DiFfRG::ScalingRootFinder::successes ( ) const
inline

Member Data Documentation

◆ acceptance

Acceptance DiFfRG::ScalingRootFinder::acceptance = Acceptance::AtTarget
protected

◆ aim_fraction

double DiFfRG::ScalingRootFinder::aim_fraction = 0.5
protected

◆ answer_found

bool DiFfRG::ScalingRootFinder::answer_found = false
protected

◆ approach_factor

double DiFfRG::ScalingRootFinder::approach_factor = 0.1
protected

◆ best_obs

double DiFfRG::ScalingRootFinder::best_obs = NAN
protected

◆ best_x

double DiFfRG::ScalingRootFinder::best_x = NAN
protected

◆ beta_max

double DiFfRG::ScalingRootFinder::beta_max = 5.
protected

◆ beta_min

double DiFfRG::ScalingRootFinder::beta_min = 0.02
protected

◆ bounds_are_hypotheses

bool DiFfRG::ScalingRootFinder::bounds_are_hypotheses = true
protected

◆ counts

Counts DiFfRG::ScalingRootFinder::counts
protected

◆ divergent_shift

double DiFfRG::ScalingRootFinder::divergent_shift = NAN
protected

◆ divergent_valid

bool DiFfRG::ScalingRootFinder::divergent_valid = false
protected

◆ divergent_x_c

double DiFfRG::ScalingRootFinder::divergent_x_c = NAN
protected

◆ endpoint_standoff

double DiFfRG::ScalingRootFinder::endpoint_standoff = 0.02
protected

◆ expansion_factor

double DiFfRG::ScalingRootFinder::expansion_factor = 2.
protected

◆ expansion_max_iter

uint DiFfRG::ScalingRootFinder::expansion_max_iter = 24
protected

◆ expansions

uint DiFfRG::ScalingRootFinder::expansions = 0
protected

◆ F

std::vector<std::pair<double, double> > DiFfRG::ScalingRootFinder::F
protected

(x, residual) for every informative failure

◆ f

FUN DiFfRG::ScalingRootFinder::f
protected

◆ have_success

bool DiFfRG::ScalingRootFinder::have_success = false
protected

◆ iter

uint DiFfRG::ScalingRootFinder::iter = 0
protected

◆ m_converged

bool DiFfRG::ScalingRootFinder::m_converged = false
protected

◆ max_iter

uint DiFfRG::ScalingRootFinder::max_iter
protected

◆ model_beta

double DiFfRG::ScalingRootFinder::model_beta = NAN
protected

◆ model_log_C

double DiFfRG::ScalingRootFinder::model_log_C = NAN
protected

◆ model_theta

double DiFfRG::ScalingRootFinder::model_theta = NAN
protected

◆ model_valid

bool DiFfRG::ScalingRootFinder::model_valid = false
protected

◆ model_x_c

double DiFfRG::ScalingRootFinder::model_x_c = NAN
protected

◆ model_x_c_prev

double DiFfRG::ScalingRootFinder::model_x_c_prev = NAN
protected

◆ obs_window

double DiFfRG::ScalingRootFinder::obs_window = 20.
protected

◆ one_sided

bool DiFfRG::ScalingRootFinder::one_sided = true
protected

◆ probed_hi_init

bool DiFfRG::ScalingRootFinder::probed_hi_init = false
protected

◆ probed_lo_init

bool DiFfRG::ScalingRootFinder::probed_lo_init = false
protected

◆ rel_tol

double DiFfRG::ScalingRootFinder::rel_tol
protected

◆ residual_window

double DiFfRG::ScalingRootFinder::residual_window = 0.
protected

◆ S

std::vector<std::pair<double, double> > DiFfRG::ScalingRootFinder::S
protected

(x, obs) for every finite evaluation

◆ seeded_exponent

double DiFfRG::ScalingRootFinder::seeded_exponent = NAN
protected

◆ target

double DiFfRG::ScalingRootFinder::target
protected

◆ theta_max

double DiFfRG::ScalingRootFinder::theta_max = 8.
protected

◆ theta_min

double DiFfRG::ScalingRootFinder::theta_min = 0.5
protected

◆ w_init

double DiFfRG::ScalingRootFinder::w_init = NAN
protected

◆ w_prev

double DiFfRG::ScalingRootFinder::w_prev = std::numeric_limits<double>::infinity()
protected

◆ w_prevprev

double DiFfRG::ScalingRootFinder::w_prevprev = std::numeric_limits<double>::infinity()
protected

◆ x_hi

double DiFfRG::ScalingRootFinder::x_hi = std::numeric_limits<double>::infinity()
protected

◆ x_hi_init

double DiFfRG::ScalingRootFinder::x_hi_init = NAN
protected

◆ x_lo_hard

double DiFfRG::ScalingRootFinder::x_lo_hard = -std::numeric_limits<double>::infinity()
protected

◆ x_lo_init

double DiFfRG::ScalingRootFinder::x_lo_init = NAN
protected

◆ x_lo_soft

double DiFfRG::ScalingRootFinder::x_lo_soft = -std::numeric_limits<double>::infinity()
protected

◆ x_rel_floor

double DiFfRG::ScalingRootFinder::x_rel_floor = 1e-13
protected

The documentation for this class was generated from the following file:
  • /home/runner/work/DiFfRG_current/DiFfRG_current/DiFfRG/include/DiFfRG/common/root_finding.hh