Skip to content
Specular Differentiation

specular.optimization.specular_gradient

specular_gradient(objective_function, initial_point, step_size='constant', max_iter=1000, tol=1e-06, *, h=None, gradient=None, line_search_gradient=None, record_history=True, step_options=None, **step_parameters)

Run SPEG, using the normalized negative specular gradient as the direction. Also available as specular.specular_gradient.

Parameters

Parameter Description
objective_function Callable returning a real scalar objective value.
initial_point Finite real scalar or nonempty one-dimensional vector.
step_size="constant" Named rule, positive constant, or callable accepting (n, x, d). See make_step_size.
max_iter=1000 Nonnegative integer limiting the number of accepted updates.
tol=1e-6 Finite, nonnegative tolerance for the unnormalized gradient norm.
h=None Positive finite scalar differentiation interval, or automatic backend-dependent intervals when omitted.
gradient=None Optional raw specular gradient callback gradient(x), matching the shape of initial_point.
line_search_gradient=None Optional raw gradient callback for a named line search's slope tests.
record_history=True Whether to record the initial point and accepted iterates.
step_options=None Mapping of options for a named or numeric step rule.
**step_parameters Additional named step options, such as a=0.5 or b=1.0.

Returns

An OptimizationResult containing the last accepted point, its objective value, the stopping reason, and optional history.

Notes

This convenience wrapper delegates to minimize with direction="speg". It tests the norm of the raw gradient before normalization. A zero gradient stops the iteration; satisfying tol does not certify a global minimum.

Options may be supplied through step_options or directly as keywords. Supplying the same option through both raises TypeError. Set step_options={"max_iter": ...} to configure the line search budget separately from the solver's max_iter.

Ordinary Armijo and Wolfe rules use classical centered differences unless line_search_gradient is supplied. Rules prefixed with specular_ use the raw specular gradient by default. The two derivative choices have different meanings; see the optimization user guide.

Examples

import specular

result = specular.specular_gradient(
    abs,
    initial_point=1.0,
    step_size="square_summable_not_summable",
    a=0.5,
    b=1.0,
    max_iter=200,
)
print(result.solution, result.func_val, result.stop_reason)
Source code in specular/optimization/solver.py
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
def specular_gradient(
    objective_function: Callable,
    initial_point: Any,
    step_size: str | float | Callable = "constant",
    max_iter: int = 1000,
    tol: float = 1e-6,
    *,
    h: float | None = None,
    gradient: Callable | None = None,
    line_search_gradient: Callable | None = None,
    record_history: bool = True,
    step_options: Mapping[str, Any] | None = None,
    **step_parameters: Any,
) -> OptimizationResult:
    """Run SPEG, the normalized negative specular-gradient method.

    Named step parameters can be supplied directly, e.g. ``a=0.1``, or in
    ``step_options``. Duplicate parameters are rejected. All iteration and
    termination behavior is provided by :func:`minimize`.
    """
    options = dict(step_options) if step_options is not None else {}
    overlap = options.keys() & step_parameters.keys()
    if overlap:
        raise TypeError(f"duplicate step parameters: {', '.join(sorted(overlap))}")
    options.update(step_parameters)
    return minimize(
        objective_function,
        initial_point,
        direction="speg",
        step_size=step_size,
        gradient=gradient,
        line_search_gradient=line_search_gradient,
        h=h,
        max_iter=max_iter,
        tol=tol,
        record_history=record_history,
        step_options=options,
    )