Levenberg-Marquardt
Manopt.LevenbergMarquardt — Function
LevenbergMarquardt(M, f, jacobian_f, p, num_components=-1; kwargs...)
LevenbergMarquardt(M, vgf, p; kwargs...)
LevenbergMarquardt(M, nlso, p; kwargs...)
LevenbergMarquardt!(M, f, jacobian_f, p, num_components=-1; kwargs...)
LevenbergMarquardt!(M, vgf, p; kwargs...)
LevenbergMarquardt!(M, nlso, p; kwargs...)compute the the Riemannian Levenberg-Marquardt algorithm [Pee93, AOT22, BB26] to solve
\[\operatorname*{arg\,min}_{p ∈ \mathcal{M}} f(p), \qquad f(p) = \frac{1}{2} \sum_{i=1}^{m} ρ_i \bigl( \lVert F_i(p) \rVert^2 \bigr)\]
where $F_i: \mathcal{M} → ℝ^{n_i}$ is the $i$th block component of length $n_i > 0$ and each $ρ_i: ℝ → ℝ$ is a robustifier function, cf. AbstractRobustifierFunction, for each such a block component. The overall residual function is denoted by $F: \mathcal{M} → ℝ^{n}$ with $n = \sum_{i=1}^{m} n_i$ and concatenates all block components.
The second block of signatures perform the optimization in-place of p.
The regularization parameter is updated using a generalized scheme proposed in [Fan06], Eq. (2.2). See also [Yua15] for other schemes. The generalized scheme offers separate thresholds for the acceptance of new points (candidate_acceptance_threshold), decreasing the regularization parameter (damping_reduction_threshold) and increasing the regularization parameter (damping_increase_threshold).
Input
M::AbstractManifold: a Riemannian manifold $\mathcal{M}$f: a residual function $f: \mathcal{M}→ℝ^m$. The residual function can be provided in two different ways- as a single function returning a vector $f(p) ∈ ℝ^m$
- as a vector of functions, where each single function returns a scalar $f_i(p) ∈ ℝ$
function_type=keyword argument.jacobian_f: the Jacobian of $f$. The Jacobian can be provided in three different ways- as a single function returning a vector of gradient vectors $\bigl(\operatorname{grad} f_i(p)\bigr)_{i=1}^m$
- as a vector of functions, where each single function returns a gradient vector $\operatorname{grad} f_i(p)$, $i=1,…,m$
- as a single function returning a (coefficient) matrix $J ∈ ℝ^{m×d}$, where $d$ is the dimension of the manifold.
AbstractBasisof the tangent space atp. The type is determined by thejacobian_type=keyword argument.p::P: a point on the manifold $\mathcal{M}$num_components: length $m$ of the vector returned by the cost function. By default its value is -1 which means that it is determined automatically by callingfone additional time. This is only possible whenevaluationisAllocatingEvaluation, for mutating evaluation this value must be explicitly specified.
You can also provide the cost and its Jacobian already as a VectorGradientFunction vgf to indicate you are working on a single block, Alternatively, passing a ManifoldNonlinearLeastSquaresObjective nlso also works.
Keyword arguments
If you provide f and its jacobian
evaluation::AbstractEvaluationType=AllocatingEvaluation(): specify whether the functions that return an array, for example a point or a tangent vector, work by allocating its result (AllocatingEvaluation) or whether they modify their input argument to return the result therein (InplaceEvaluation). Since usually the first argument is the manifold, the modified argument is the second.function_type=FunctionVectorialType: anAbstractVectorialTypespecifying the type of cost function provided.jacobian_type=FunctionVectorialType: anAbstractVectorialTypespecifying the type of Jacobian provided.
as well as then these are already combined in a single VectorGradientFunction vgf
robustifier::AbstractRobustifierFunction=IdentityRobustifier(): for the robust variant, specify how the robustification is meant to take place.- if you provide a single vectorial function and its Jacobian, a single robustifer is applied to every component function of this vectorial function (each component is a block in the sum)
- if you provide a vector of
VectorGradientFunctions, each needs a robustifier.
evaluation::AbstractEvaluationType=AllocatingEvaluation(): specify whether the functions that return an array, for example a point or a tangent vector, work by allocating its result (AllocatingEvaluation) or whether they modify their input argument to return the result therein (InplaceEvaluation). Since usually the first argument is the manifold, the modified argument is the second.
as well as in general using the model improvement parameter $m_k$ in several places, cf [BB26]
candidate_acceptance_threshold=0.2: sufficient model improvement $η ∈ (0,1)$, i.e. $m_k > η$ to accept a candidate pointdamping_increase_factor=5.0: factor $β_{\text{i}}$ to increase damping, when the model is inaccuratedamping_increase_threshold=candidate_acceptance_threshold: threshold $η_{\text{l}}$ the value $m_k$has to be below to increase damping. The default yields, that we increase damping when we reject a candidate.damping_reduction_factor= 1 / damping_increase_factor: factor $β_{\text{d}}$ to reduce damping, when the model is accuratedamping_reduction_threshold=Inf: threshold $β_{\text{d}}$ to reduce damping, when the model is accurate The default means, that we never reduce damping.damping_term_min = 0.1: lower bound $μ_{\text{l}}$ for the damping $μ_k$ throughout the iterationsdamping_term_max = Inf: upper bound $μ_{\text{u}}$ for the damping $μ_k$ throughout the iterationsinitial_damping_term=damping_term_min: initial damping $μ_0$initial_residual_values = zeros(m): a cache for the vector of residuals,mis the number of residual blocksinitial_jacobian_matrices: a cache for the evaluated Jacobians (currently only used ifuse_unified_basis = true, then initialized to a vector of jacobian matrices, otherwise ignored)retraction_method::AbstractRetractionMethod=default_retraction_method(M, typeof(p)): a retraction $\operatorname{retr}$ to use, see the section on retractionsscaling_threshold = 1.0e-6: a thresholdεto bound the scaling parameterαin the robust case away from1, seeget_LevenbergMarquardt_scalingscaling_mode = :Strict: specify the scaling stabilization mode, seeget_LevenbergMarquardt_scalingstopping_criterion::StoppingCriterion=StopAfterIteration(500)|StopWhenGradientNormLess(1.0e-12)|StopWhenStepsizeLess(1.0e-12): a functor indicating that the stopping criterion is fulfilledsub_objective: specify the objective for the surrogate sub problem to solver in every iteration. This is set depending on theuse_unified_basis- if
trueto theLevenbergMarquardtLinearSurrogateCoordinatesObjectivewhich always works in coordinates of one single basis per tangent space and allows to cache Jacobian evaluations - if
falseto theLevenbergMarquardtLinearSurrogateObjectivethat can work either with linear operators or in (even different) coordinates.
This keyword is ignored if you set the
sub_problemand/orsub_statekeyword directly- if
sub_problem =DefaultManoptProblem(TangentSpace(M, p), sub_objective): specify the sub problem to be solved. This should usually be phrased on the tangent space at the current iteratesub_state =ConjugateResidualState(TangentSpace(M, p), sub_objective): specify the solver for the surrogate, see alsoconjugate_residualuse_unified_basis = false: specify to use a single basis for all Jacobian evaluations at a certain iterate, seesub_objectivethis requires that all Jacobians involved are of typeCoefficientVectorialType, since only then a jacobian can be represented as a matrix, and then here unified in the sense that all use the same basis.
All other keyword arguments are passed to decorate_state! for state decorators or decorate_objective! for objective decorators, respectively.
Output
The obtained approximate minimizer $p^*$. To obtain the whole final state of the solver, see get_solver_return for details, especially the return_state= keyword.
Manopt.LevenbergMarquardt! — Function
LevenbergMarquardt(M, f, jacobian_f, p, num_components=-1; kwargs...)
LevenbergMarquardt(M, vgf, p; kwargs...)
LevenbergMarquardt(M, nlso, p; kwargs...)
LevenbergMarquardt!(M, f, jacobian_f, p, num_components=-1; kwargs...)
LevenbergMarquardt!(M, vgf, p; kwargs...)
LevenbergMarquardt!(M, nlso, p; kwargs...)compute the the Riemannian Levenberg-Marquardt algorithm [Pee93, AOT22, BB26] to solve
\[\operatorname*{arg\,min}_{p ∈ \mathcal{M}} f(p), \qquad f(p) = \frac{1}{2} \sum_{i=1}^{m} ρ_i \bigl( \lVert F_i(p) \rVert^2 \bigr)\]
where $F_i: \mathcal{M} → ℝ^{n_i}$ is the $i$th block component of length $n_i > 0$ and each $ρ_i: ℝ → ℝ$ is a robustifier function, cf. AbstractRobustifierFunction, for each such a block component. The overall residual function is denoted by $F: \mathcal{M} → ℝ^{n}$ with $n = \sum_{i=1}^{m} n_i$ and concatenates all block components.
The second block of signatures perform the optimization in-place of p.
The regularization parameter is updated using a generalized scheme proposed in [Fan06], Eq. (2.2). See also [Yua15] for other schemes. The generalized scheme offers separate thresholds for the acceptance of new points (candidate_acceptance_threshold), decreasing the regularization parameter (damping_reduction_threshold) and increasing the regularization parameter (damping_increase_threshold).
Input
M::AbstractManifold: a Riemannian manifold $\mathcal{M}$f: a residual function $f: \mathcal{M}→ℝ^m$. The residual function can be provided in two different ways- as a single function returning a vector $f(p) ∈ ℝ^m$
- as a vector of functions, where each single function returns a scalar $f_i(p) ∈ ℝ$
function_type=keyword argument.jacobian_f: the Jacobian of $f$. The Jacobian can be provided in three different ways- as a single function returning a vector of gradient vectors $\bigl(\operatorname{grad} f_i(p)\bigr)_{i=1}^m$
- as a vector of functions, where each single function returns a gradient vector $\operatorname{grad} f_i(p)$, $i=1,…,m$
- as a single function returning a (coefficient) matrix $J ∈ ℝ^{m×d}$, where $d$ is the dimension of the manifold.
AbstractBasisof the tangent space atp. The type is determined by thejacobian_type=keyword argument.p::P: a point on the manifold $\mathcal{M}$num_components: length $m$ of the vector returned by the cost function. By default its value is -1 which means that it is determined automatically by callingfone additional time. This is only possible whenevaluationisAllocatingEvaluation, for mutating evaluation this value must be explicitly specified.
You can also provide the cost and its Jacobian already as a VectorGradientFunction vgf to indicate you are working on a single block, Alternatively, passing a ManifoldNonlinearLeastSquaresObjective nlso also works.
Keyword arguments
If you provide f and its jacobian
evaluation::AbstractEvaluationType=AllocatingEvaluation(): specify whether the functions that return an array, for example a point or a tangent vector, work by allocating its result (AllocatingEvaluation) or whether they modify their input argument to return the result therein (InplaceEvaluation). Since usually the first argument is the manifold, the modified argument is the second.function_type=FunctionVectorialType: anAbstractVectorialTypespecifying the type of cost function provided.jacobian_type=FunctionVectorialType: anAbstractVectorialTypespecifying the type of Jacobian provided.
as well as then these are already combined in a single VectorGradientFunction vgf
robustifier::AbstractRobustifierFunction=IdentityRobustifier(): for the robust variant, specify how the robustification is meant to take place.- if you provide a single vectorial function and its Jacobian, a single robustifer is applied to every component function of this vectorial function (each component is a block in the sum)
- if you provide a vector of
VectorGradientFunctions, each needs a robustifier.
evaluation::AbstractEvaluationType=AllocatingEvaluation(): specify whether the functions that return an array, for example a point or a tangent vector, work by allocating its result (AllocatingEvaluation) or whether they modify their input argument to return the result therein (InplaceEvaluation). Since usually the first argument is the manifold, the modified argument is the second.
as well as in general using the model improvement parameter $m_k$ in several places, cf [BB26]
candidate_acceptance_threshold=0.2: sufficient model improvement $η ∈ (0,1)$, i.e. $m_k > η$ to accept a candidate pointdamping_increase_factor=5.0: factor $β_{\text{i}}$ to increase damping, when the model is inaccuratedamping_increase_threshold=candidate_acceptance_threshold: threshold $η_{\text{l}}$ the value $m_k$has to be below to increase damping. The default yields, that we increase damping when we reject a candidate.damping_reduction_factor= 1 / damping_increase_factor: factor $β_{\text{d}}$ to reduce damping, when the model is accuratedamping_reduction_threshold=Inf: threshold $β_{\text{d}}$ to reduce damping, when the model is accurate The default means, that we never reduce damping.damping_term_min = 0.1: lower bound $μ_{\text{l}}$ for the damping $μ_k$ throughout the iterationsdamping_term_max = Inf: upper bound $μ_{\text{u}}$ for the damping $μ_k$ throughout the iterationsinitial_damping_term=damping_term_min: initial damping $μ_0$initial_residual_values = zeros(m): a cache for the vector of residuals,mis the number of residual blocksinitial_jacobian_matrices: a cache for the evaluated Jacobians (currently only used ifuse_unified_basis = true, then initialized to a vector of jacobian matrices, otherwise ignored)retraction_method::AbstractRetractionMethod=default_retraction_method(M, typeof(p)): a retraction $\operatorname{retr}$ to use, see the section on retractionsscaling_threshold = 1.0e-6: a thresholdεto bound the scaling parameterαin the robust case away from1, seeget_LevenbergMarquardt_scalingscaling_mode = :Strict: specify the scaling stabilization mode, seeget_LevenbergMarquardt_scalingstopping_criterion::StoppingCriterion=StopAfterIteration(500)|StopWhenGradientNormLess(1.0e-12)|StopWhenStepsizeLess(1.0e-12): a functor indicating that the stopping criterion is fulfilledsub_objective: specify the objective for the surrogate sub problem to solver in every iteration. This is set depending on theuse_unified_basis- if
trueto theLevenbergMarquardtLinearSurrogateCoordinatesObjectivewhich always works in coordinates of one single basis per tangent space and allows to cache Jacobian evaluations - if
falseto theLevenbergMarquardtLinearSurrogateObjectivethat can work either with linear operators or in (even different) coordinates.
This keyword is ignored if you set the
sub_problemand/orsub_statekeyword directly- if
sub_problem =DefaultManoptProblem(TangentSpace(M, p), sub_objective): specify the sub problem to be solved. This should usually be phrased on the tangent space at the current iteratesub_state =ConjugateResidualState(TangentSpace(M, p), sub_objective): specify the solver for the surrogate, see alsoconjugate_residualuse_unified_basis = false: specify to use a single basis for all Jacobian evaluations at a certain iterate, seesub_objectivethis requires that all Jacobians involved are of typeCoefficientVectorialType, since only then a jacobian can be represented as a matrix, and then here unified in the sense that all use the same basis.
All other keyword arguments are passed to decorate_state! for state decorators or decorate_objective! for objective decorators, respectively.
Output
The obtained approximate minimizer $p^*$. To obtain the whole final state of the solver, see get_solver_return for details, especially the return_state= keyword.
Options
Manopt.LevenbergMarquardtState — Type
LevenbergMarquardtState{P,T} <: AbstractGradientSolverStateDescribes a Gradient based descent algorithm, with
Fields
damping_term: current value of the damping termdamping_term_min: lower bound for the damping termdamping_term_max: upper bound for the damping termdamping_increase_factor: improvement quotient exceedsdamping_reduction_threshold.damping_reduction_threshold: threshold for the improvement quotient above which the damping term is reduced by multiplying it withβ_reduction.damping_increase_threshold: threshold for the improvement quotient below which the damping term is increased by multiplying it withβ.direction: the current search direction, which is the solution of the linearized subproblem in each iteration.candidate_acceptance_threshold: Scaling factor for the sufficient cost decrease threshold required to accept new proposal points. Allowed range:0 < η < 1.callbacks: the callbacks dictionaryjacobian_matrices: the current Jacobian of $F$ in matrix form per block, hence a vector of matrices. This is (by default) set tonothingif another representation is used.minimum_acceptable_model_improvement: the minimum improvement in the model function that is required to accept a new point; if this is not met, the new point is rejected and the damping term is increased.p::P: a point on the manifold $\mathcal{M}$ storing the current iterateretraction_method::AbstractRetractionMethod: a retraction $\operatorname{retr}$ to use, see the section on retractionsresidual_values: values of the residuals calculated in the solver setup or the previous iterationstop::StoppingCriterion: a functor indicating that the stopping criterion is fulfilledsub_problem::Union{AbstractManoptProblem, F}: specify a problem for a solver or a closed form solution function, which can be allocating or in-place.sub_state::Union{AbstractManoptProblem, F}: a state to specify the sub solver to use. For a closed form solution, this indicates the type of function.X::T: a tangent vector at the point $p$ on the manifold $\mathcal{M}$
Constructor
LevenbergMarquardtState(M, sub_problem, sub_state, initial_residual_values, initial_jacobian; kwargs...)Generate the Levenberg-Marquardt solver state.
Keyword arguments
The following fields are keyword arguments
candidate_acceptance_threshold = 0.2,damping_increase_factor = 5.0damping_reduction_factor = 0.5damping_term_min = 0.1damping_term_max = Infdamping_term = damping_term_mindamping_reduction_threshold = Infdamping_increase_threshold = candidate_acceptance_thresholddirection = copy(M, p, X)p =rand(M)X =zero_vector(M, p)retraction_method::AbstractRetractionMethod=default_retraction_method(M, typeof(p)): a retraction $\operatorname{retr}$ to use, see the section on retractionsstopping_criterion::StoppingCriterion=StopAfterIteration(200)|StopWhenGradientNormLess(1e-12)|StopWhenStepsizeLess(1e-12): a functor indicating that the stopping criterion is fulfilledcallbacks::D = Dict{Symbol,Function}(): provided callback functions given as a dictionary with symbols as keysminimum_acceptable_model_improvement::Real = eps(number_eltype(p))
See also
Solver Internals
Internal functions
Internally within the sub solvers both a linear operator, sometimes as a full matrix, and a vector as right hand side of a linear system have to be constructed. The following functions accompany this.
Manopt.default_lm_lin_solve! — Function
default_lm_lin_solve!(sk, JJ::AbstractMatrix, grad_f_c)Solve the linear system of equations of the normal equations JJ \ grad_f_c where JJ is a symmetric positive definite matrix and save the result to sk. In case of numerical errors the PosDefException is caught and the default symmetric solver (Symmetric(JJ) \ grad_f_c) is used.
The function is intended to be used with LevenbergMarquardt.
Manopt.add_normal_vector_field! — Function
add_normal_vector_field!(M::AbstractManifold, X, o::AbstractFirstOrderVectorFunction, r::AbstractRobustifierFunction, p)
add_normal_vector_field!(M::AbstractManifold, c, o::AbstractFirstOrderVectorFunction, r::AbstractRobustifierFunction, p, B::AbstractBasis)Add the contribution of o / r to the normal linear operator tangent vector in X or c. See get_normal_vector_field for the mathematical details. Note that this is done per every block (vectorial function with its robustifier) of the underlying ManifoldNonlinearLeastSquaresObjective and summed up.
See also get_normal_linear_operator for evaluating the corresponding linear operator of the (normal) linear system, and get_LevenbergMarquardt_scaling for details on the scaling and computation of $C$.
Manopt.add_normal_linear_operator! — Function
add_normal_linear_operator!(
M::AbstractManifold, A::AbstractMatrix, o::AbstractFirstOrderVectorFunction,
r::AbstractRobustifierFunction, p, basis::AbstractBasis;
value_cache = get_value(M, o, p), ε::Real, mode::Symbol
)Add the contribution of a single block (vectorial function with its robustifier) to the linear normal operator, i.e. compute $A += J_F^*(p)[C^T C J_F(p)[X]]$ in-place of A for the given block. See get_normal_linear_operator for details
Manopt.add_linear_operator_coord! — Function
add_linear_operator_coord!(
M::AbstractManifold, y::AbstractVector, lmsco::LevenbergMarquardtLinearSurrogateCoordinatesObjective, p, cX::AbstractVector
)Add the (Triggs correction, residual-like) linear operator corresponding to the lmsco surrogate to vector y. It is assumed that lmsco.value_cache has been filled in step_solver! of LevenbergMarquardt, so we can just use it here.
Technical details
The LevenbergMarquardt solver requires the following functions of a manifold to be available
- A
retract!(M, q, p, X); it is recommended to set thedefault_retraction_methodto a favourite retraction. If this default is set, aretraction_method=does not have to be specified. - the
normas well, to stop when the norm of the gradient is small, but if you implementedinner, the norm is provided already. - A
copyto!(M, q, p)andcopy(M,p)for points.
Literature
- [AOT22]
- S. Adachi, T. Okuno and A. Takeda. Riemannian Levenberg-Marquardt Method with Global and Local Convergence Properties. ArXiv Preprint (2022).
- [BB26]
- M. Baran and R. Bergmann. A modified Riemannian Levenberg-Marquardt algorithm for robust and constraint optimization on manifolds (2026), arXiv:2606.23560 [math.OC].
- [Fan06]
- J. Fan. Convergence Rate of The Trust Region Method for Nonlinear Equations Under Local Error Bound Condition. Computational Optimization and Applications 34, 215–227 (2006).
- [Pee93]
- R. Peeters. On a Riemannian version of the Levenberg-Marquardt algorithm. Serie Research Memoranda 0011 (VU University Amsterdam, Faculty of Economics, Business Administration and Econometrics, 1993).
- [Yua15]
- Y.-x. Yuan. Recent advances in trust region algorithms. Mathematical Programming 151, 249–281 (2015).