"speg", its alias "specular_gradient", or a custom callable accepting (n, x).
f=None
Scalar-valued objective for numerical specular differentiation. Required for a named method unless gradient is supplied.
gradient=None
Raw specular gradient callback gradient(x). Takes precedence over numerical differentiation of f.
h=None
Concrete, finite, positive scalar differentiation interval. If omitted, the selected backend chooses intervals automatically.
Returns
A callable with the interface:
direction(n,x,*,gradient_value=None)
It returns a finite real scalar or a one-dimensional NumPy array with the
same shape as x. The iteration index n must be an integer at least one.
Notes
SPEG returns the negative unit vector of the raw specular gradient, or zero
when that gradient is exactly zero. gradient_value can reuse a previously
computed raw gradient. This cached value must match the shape of x.
A custom method(n, x) is used directly, without normalization, and ignores
gradient_value. Callbacks receive private copies of vector points.
Both points and returned directions must be finite scalars or nonempty
one-dimensional vectors with exactly matching shapes.
Numerical differentiation uses the currently selected
calculation backend. An explicit gradient callback
performs its own computation.
defmake_direction(method:str|Callable[[int,Point],Any]="speg",*,f:Callable[[Point],Any]|None=None,gradient:Callable[[Point],Any]|None=None,h:Any=None,)->Direction:r"""Create ``direction(n, x, *, gradient_value=None)``. ``"speg"`` (also ``"specular_gradient"``) returns the negative unit specular gradient, or zero when the gradient is exactly zero. Supply a raw ``gradient(x)`` callback or an objective ``f`` for numerical specular differentiation using the currently selected backend. ``h=None`` keeps that backend's automatic differentiation interval. A callable ``method(n, x)`` supplies a custom direction without additional normalization. Iterations are numbered from one. All returned directions must be finite and match the scalar or vector shape of ``x`` exactly. Callbacks receive a private copy of vector points. ``gradient_value`` optionally reuses a previously evaluated raw gradient for SPEG. Custom methods do not use this cache. """ifnotisinstance(method,str)andnotcallable(method):raiseTypeError("method must be a direction name or a callable")ifisinstance(method,str)andmethodnotin{"speg","specular_gradient"}:raiseValueError(f"unknown direction method: {method!r}")iffisnotNoneandnotcallable(f):raiseTypeError("f must be callable")ifgradientisnotNoneandnotcallable(gradient):raiseTypeError("gradient must be callable")validated_h=NoneifhisNoneelsecalculation._positive_step(h)ifisinstance(method,str)andfisNoneandgradientisNone:raiseValueError("SPEG requires f or a raw gradient callback")defdirection(n:int,x:Any,*,gradient_value:Any=None)->Point:ifisinstance(n,(bool,np.bool_)):raiseTypeError("n must be an integer")try:iteration=operator.index(n)exceptTypeErrorasexc:raiseTypeError("n must be an integer")fromexcifiteration<1:raiseValueError("n must be at least one")point=_as_point(x)shape=np.shape(point)ifcallable(method):value=_as_point(method(iteration,point),name="direction")else:ifgradient_valueisnotNone:raw=gradient_valueelifgradientisnotNone:raw=gradient(point)elifshape==():raw=calculation.derivative(f,point,h=validated_h)else:raw=calculation.gradient(f,point,h=validated_h)value=_as_point(raw,name="gradient")ifnp.shape(value)!=shape:name="direction"ifcallable(method)else"gradient"raiseValueError(f"{name} must have exactly the same shape as x")returnvalueifcallable(method)else_negative_unit(value)returndirection