Problem types (AggregationLevel)

optimagic can optimize three kinds of objective functions: scalar, least-squares, and likelihood. Internally these are represented by AggregationLevel.

You tell optimagic which kind you have by marking the objective function with a decorator from optimagic.mark (@om.mark.least_squares, @om.mark.likelihood, or optionally @om.mark.scalar). That mark changes:

  1. What your function should return (a single number vs a vector of contributions or residuals).

  2. Which specialized optimizers you can use (for example pounders for least-squares, or BHHH for likelihood).

  3. How error penalties and derivatives are interpreted when something goes wrong (see How to handle errors during optimization).

Any marked function can still be solved with a normal scalar optimizer; optimagic aggregates the vector output when needed (sum of squares for least-squares, sum of contributions for likelihood).

Scalar problems

This is the default. Your function returns a single number — the value to minimize (or maximize).

import optimagic as om
import numpy as np


# @om.mark.scalar is optional; unmarked functions are treated as scalar
def sphere(params):
    return params @ params


om.minimize(sphere, params=np.arange(3), algorithm="scipy_lbfgsb")

Use this whenever you do not have least-squares or likelihood structure to exploit.

Least-squares problems

Mark the function with @om.mark.least_squares and return the residuals (a vector or pytree), not the sum of squared residuals.

@om.mark.least_squares
def ls_sphere(params):
    return params  # residuals; optimagic forms sum of squares if needed

Why mark it? Specialized least-squares solvers can use the residual structure and are often much faster than treating \(f(x)=\sum_i r_i(x)^2\) as a black-box scalar. If you only return the scalar sum of squares, those solvers cannot be used.

See How to write objective functions for a short usage example.

Likelihood problems

Mark the function with @om.mark.likelihood and return a vector (or pytree) of per-observation log-likelihood contributions, not a single summed log-likelihood.

@om.mark.likelihood
def loglike_contributions(params):
    # return one log-density value per observation (an array), not their sum
    ...

Sign / maximize vs minimize: return the actual log-likelihood contributions (the quantities you would sum to get \(\ell(\theta)\)). Prefer maximize() for maximum likelihood; optimagic flips the sign internally for the solver. If you prefer minimize(), return negative log-likelihood contributions instead.

Do not return only the summed scalar log-likelihood if you want likelihood-specific optimizers — they need the contributions.

For estimation workflows built on likelihood functions, see also Estimagic.

How this relates to AggregationLevel

Problem

Decorator

Typical return

AggregationLevel

Scalar

none or @om.mark.scalar

float

SCALAR

Least-squares

@om.mark.least_squares

residual vector

LEAST_SQUARES

Likelihood

@om.mark.likelihood

contribution vector

LIKELIHOOD

Optimizers are also tagged with a solver_type of the same enum (see Internal optimizers for optimagic). Matching the mark on your function to the solver type is what lets optimagic pick the right internal representation.