kups.relaxation.transforms.linesearch
¶
Per-system line searches that reproduce ASE's implementations.
Two transforms that rescale an incoming descent direction d by a
per-system step length t. Like every other transform in this package,
the search is taken per system: φ(t), φ'(t) and the accept /
backtrack decision are arrays of shape (n_systems,) keyed on the
system ids, so a system that is already satisfied never throttles the step
of one that is not, and a batched run is bit-identical to running each
system on its own.
The two searches reproduce ASE's two line searches step-for-step (a single system matches ASE to floating-point tolerance):
- :class:
ScaleByBacktrackingLinesearchis :class:ase.utils.linesearcharmijoLineSearchArmijo: quadratic-interpolation backtracking enforcing the Armijo sufficient-decrease condition, with thet ← max(t_quad, t/10)floor. - :class:
ScaleByMoreThuenteLinesearchis :class:ase.utils.linesearchLineSearch: the MINPACK More–Thuente search (dcsrch/dcstep) targeting the strong Wolfe conditions, which ASE'sLBFGS(use_line_search=True)uses and which pairs naturally with :class:ScaleByAseLbfgs.
ASE bakes a per-atom maxstep clamp into the search (via determine_step);
here that clamp is left to the separate :class:MaxStepSize transform, so
determine_step is the identity and the searches reproduce the pure
algorithms. ASE also fixes the initial trial step at 1.0; t_init = 1.0
(the default) reproduces ASE exactly.
API convention¶
Following the optax composability pattern, the updates passed to
:meth:update is the descent direction d produced by the preceding
transforms (e.g. -H⁻¹∇L once the L-BFGS preconditioner is sign-flipped),
and the raw gradient ∇L arrives as the grad keyword. The search emits
t · d per system, so it belongs at the tail of a chain:
.. code-block:: python
from kups.relaxation.optimizer import chain
from kups.relaxation.transforms import ScaleByAseLbfgs, ScaleByMoreThuenteLinesearch
import optax
optimizer = chain(
ScaleByAseLbfgs(memory_size=10), # H⁻¹∇L
optax.scale(-1.0), # descent direction d = -H⁻¹∇L
ScaleByMoreThuenteLinesearch(), # t · d
)
Each step :class:kups.relaxation.propagator.RelaxationPropagator supplies
the current per-system energies (energies), the raw gradient (grad)
and a value_and_grad_fn that returns the per-system energies and gradient
at a trial point. A system whose direction is not a descent direction
(∇L · d ≥ 0) is left unmoved (t = 0).
ValueAndGradFn = Callable[[PyTree], tuple[Table[SupportsSorting, Array], PyTree]]
¶
Maps trial params to (per-system energies, gradient pytree).
LineSearchState
¶
Line-search state.
Attributes:
| Name | Type | Description |
|---|---|---|
index_prefix |
PyTree
|
Tree prefix whose leaves are |
prev_phi0 |
Array
|
Previous step's per-system energies, |
Source code in src/kups/relaxation/transforms/linesearch.py
ScaleByBacktrackingLinesearch
¶
Bases: Optimizer[Params, LineSearchState]
Per-system Armijo backtracking line search — ASE LineSearchArmijo.
Rescales the incoming descent direction by a per-system step t: it shrinks
t by quadratic interpolation (floored at t/10) until the step meets the
Armijo sufficient-decrease condition, deciding per system. The first trial uses
a Nocedal & Wright eq. 3.60 estimate from the previous step's energy (clamped
to [a_min, a_max], else t_init). See the module docstring for the chain
convention.
Attributes:
| Name | Type | Description |
|---|---|---|
c1 |
float
|
Armijo sufficient-decrease constant ( |
a_min |
float
|
Smallest allowed step; the search freezes a system that reaches it. Also the lower clamp on the eq. 3.60 initial-step estimate. |
a_max |
float
|
Upper clamp on the eq. 3.60 initial-step estimate; above it the
first trial falls back to |
max_steps |
int
|
Maximum backtracking iterations. |
t_init |
float
|
Initial trial step when no estimate applies, rounded to |
Source code in src/kups/relaxation/transforms/linesearch.py
ScaleByMoreThuenteLinesearch
¶
Bases: Optimizer[Params, LineSearchState]
Per-system More–Thuente line search — ASE LineSearch.
Brackets and refines a step meeting the strong Wolfe conditions via the
MINPACK dcsrch/dcstep algorithm, deciding per system. This is the
search ASE's LBFGS(use_line_search=True) uses; it pairs naturally with
:class:ScaleByAseLbfgs, whose secant updates rely on the curvature
condition. See the module docstring for the chain convention.
Attributes:
| Name | Type | Description |
|---|---|---|
c1 |
float
|
Armijo sufficient-decrease constant ( |
c2 |
float
|
Curvature constant ( |
t_init |
float
|
Initial trial step. |
stpmin |
float
|
Smallest step the search will return. |
stpmax |
float
|
Largest step the search will return. |
xtol |
float
|
Relative bracket-width tolerance ending the search. |
xtrapl |
float
|
Lower extrapolation factor while bracketing. |
xtrapu |
float
|
Upper extrapolation factor while bracketing. |
max_steps |
int
|
Maximum combined bracketing + zoom iterations. |