Extensions
LineSearches.jl
Manopt can be used with line search algorithms implemented in LineSearches.jl. This can be illustrated by the following example of optimizing Rosenbrock function constrained to the unit sphere.
using Manopt, Manifolds, LineSearches
# define objective function and its gradient
p = [1.0, 100.0]
function rosenbrock(::AbstractManifold, x)
val = zero(eltype(x))
for i in 1:(length(x) - 1)
val += (p[1] - x[i])^2 + p[2] * (x[i + 1] - x[i]^2)^2
end
return val
end
function rosenbrock_grad!(M::AbstractManifold, storage, x)
storage .= 0.0
for i in 1:(length(x) - 1)
storage[i] += -2.0 * (p[1] - x[i]) - 4.0 * p[2] * (x[i + 1] - x[i]^2) * x[i]
storage[i + 1] += 2.0 * p[2] * (x[i + 1] - x[i]^2)
end
project!(M, storage, x, storage)
return storage
end
# define constraint
n_dims = 5
M = Manifolds.Sphere(n_dims)
# set initial point
x0 = vcat(zeros(n_dims - 1), 1.0)
# use LineSearches.jl HagerZhang method with Manopt.jl quasiNewton solver
ls_hz = Manopt.LineSearchesStepsize(M, LineSearches.HagerZhang())
x_opt = quasi_Newton(
M,
rosenbrock,
rosenbrock_grad!,
x0;
stepsize=ls_hz,
evaluation=InplaceEvaluation(),
stopping_criterion=StopAfterIteration(1000) | StopWhenGradientNormLess(1e-6),
return_state=true,
)# Solver state for `Manopt.jl`s Quasi Newton Method
After 10 iterations
## Parameters
* direction update: limited memory InverseBFGS (size 5) initial scaling 1.0and ParallelTransport() as vector transport.
* retraction method: StabilizedRetraction()
* vector transport method: ParallelTransport()
## Stepsize
LineSearchesStepsize(HagerZhang{Float64, Base.RefValue{Bool}}
delta: Float64 0.1
sigma: Float64 0.9
alphamax: Float64 Inf
rho: Float64 5.0
epsilon: Float64 1.0e-6
gamma: Float64 0.66
linesearchmax: Int64 50
psi3: Float64 0.1
display: Int64 0
mayterminate: Base.RefValue{Bool}
cache: Nothing nothing
check_flatness: Bool false
; retraction_method=StabilizedRetraction(), vector_transport_method=ParallelTransport())
## Stopping criterion
Stop When _one_ of the following are fulfilled:
* Max Iteration 1000: not reached
* |grad f| < 1.0e-6: reached
Overall: reached
This indicates convergence: NoIn general this defines the following new stepsize
Manopt.LineSearchesStepsize β TypeLineSearchesStepsize <: StepsizeWrapper for line searches available in the LineSearches.jl library.
Constructors
LineSearchesStepsize(M::AbstractManifold, linesearch; kwargs...
LineSearchesStepsize(
linesearch;
retraction_method=ExponentialRetraction(),
vector_transport_method=ParallelTransport(),
)Wrap linesearch (for example HagerZhang or MoreThuente). The initial step selection from Linesearches.jl is not yet supported and the value 1.0 is used.
Keyword Arguments
retraction_method=default_retraction_method(M, typeof(p)): a retraction $\operatorname{retr}$ to use, see the section on retractionsvector_transport_method=default_vector_transport_method(M, typeof(p)): a vector transport $\mathcal T_{β ββ }$ to use, see the section on vector transports
Manifolds.jl
Loading Manifolds.jl introduces the following additional functions
Manopt.max_stepsize β Methodmax_stepsize(M::FixedRankMatrices, p)Return a reasonable guess of maximum step size on FixedRankMatrices following the choice of typical distance in Matlab Manopt, the dimension of M. See this note
Manopt.max_stepsize β Methodmax_stepsize(M::Hyperrectangle, p)The default maximum stepsize for Hyperrectangle manifold with corners is maximum of distances from p to each boundary.
Manopt.max_stepsize β Methodmax_stepsize(M::TangentBundle, p)Tangent bundle has injectivity radius of either infinity (for flat manifolds) or 0 (for non-flat manifolds). This makes a guess of what a reasonable maximum stepsize on a tangent bundle might be.
ManifoldsBase.mid_point β Functionmid_point(M, p, q, x)
mid_point!(M, y, p, q, x)Compute the mid point between p and q. If there is more than one mid point of (not necessarily minimizing) geodesics (for example on the sphere), the one nearest to x is returned (in place of y).
Internally, Manopt.jl provides the two additional functions to choose some Euclidean space when needed as
Manopt.Rn β FunctionRn(args; kwargs...)
Rn(s::Symbol=:Manifolds, args; kwargs...)A small internal helper function to choose a Euclidean space. By default, this uses the DefaultManifold unless you load a more advanced Euclidean space like Euclidean from Manifolds.jl
Manopt.Rn_default β FunctionRn_default()Specify a default value to dispatch Rn on. This default is set to Manifolds, indicating, that when this package is loded, it is the preferred package to ask for a vector space space.
The default within Manopt.jl is to use the DefaultManifold from ManifoldsBase.jl. If you load Manifolds.jl this switches to using Euclidan.
JuMP.jl
Manopt can be used from within JuMP.jl. The manifold is provided in the @variable macro. Note that until now, only variables (points on manifolds) are supported, that are arrays, especially structs do not yet work. The algebraic expression of the objective function is specified in the @objective macro. The descent_state_type attribute specifies the solver.
using JuMP, Manopt, Manifolds
model = Model(Manopt.JuMP_Optimizer)
# Change the solver with this option, `GradientDescentState` is the default
set_attribute(model, "descent_state_type", GradientDescentState)
@variable(model, U[1:2, 1:2] in Stiefel(2, 2), start = 1.0)
@objective(model, Min, sum((A - U) .^ 2))
optimize!(model)
solution_summary(model)Several functions from the Mathematical Optimization Interface (MOI) are extended when both Manopt.jl and JuMP.jl are loaded:
Manopt.JuMP_Optimizer β FunctionManopt.JuMP_Optimizer()Represent a solver from Manopt.jl within the MathOptInterface (MOI) framework. See ManoptOptimizer for the fields and their meaning.
Internal functions
JuMP.build_variable β FunctionJuMP.build_variable(::Function, func, m::ManifoldsBase.AbstractManifold)Build a JuMP.VariablesConstrainedOnCreation object containing variables and the ManifoldSet in which they should belong as well as the shape that can be used to go from the vectorized MOI representation to the shape of the manifold, that is, ManifoldPointArrayShape.
MathOptInterface.add_constrained_variables β FunctionMOI.add_constrained_variables(model::ManoptOptimizer, set::ManifoldSet)Add dimension(set) variables constrained in set and return the list of variable indices that can be used to reference them as well a constraint index for the constraint enforcing the membership of the variables manifold as a set.
MathOptInterface.copy_to β FunctionMOI.copy_to(dest::ManoptOptimizer, src::MOI.ModelLike)Because supports_incremental_interface(dest) is true, this simply uses default_copy_to and copies the variables with add_constrained_variables and the objective sense with set.
MathOptInterface.empty! β FunctionMOI.empty!(model::ManoptOptimizer)Clear all model data from model but keep the options set.
MathOptInterface.dimension β FunctionMOI.dimension(set::ManifoldSet)Return the representation size of points on the (vectorized in representation) manifold. As the MOI variables are real, this means if the representation_size yields (in product) n, this refers to the vectorized point / tangent vector from (a subset of $β^n$).
Note that this is not the dimension of the manifold itself, but the vector length of the vectorized representation of the manifold.
MathOptInterface.supports_add_constrained_variables β FunctionMOI.supports_add_constrained_variables(::ManoptOptimizer, ::Type{<:ManifoldSet})Return true indicating that ManoptOptimizer support optimization on variables constrained to belong in a vectorized manifold.
MathOptInterface.get β FunctionMOI.get(::ManoptOptimizer, ::MOI.SolverVersion)Return the version of the Manopt solver, it corresponds to the version of Manopt.jl.
MOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return last value set by set(model, attr, value).
MOI.get(::ManoptOptimizer, ::MOI.SolverName)Return the name of the ManoptOptimizer with the value of the descent_state_type option.
MOI.get(model::ManoptOptimizer, ::MOI.NumberOfVariables)Return the number of variables added in the model, this corresponds to the dimension of the ManifoldSet.
MOI.get(model::ManoptOptimizer, ::MOI.ObjectiveSense)Return the objective sense, defaults to FEASIBILITY_SENSE if no sense has already been set.
MOI.get(model::ManoptOptimizer, ::MOI.ResultCount)Return OPTIMIZE_NOT_CALLED if optimize! hasn't been called yet and LOCALLY_SOLVED otherwise indicating that the solver has solved the problem to local optimality the value of RawStatusString for more details on why the solver stopped.
MOI.get(model::ManoptOptimizer, ::MOI.ResultCount)Return 0 if optimize! hasn't been called yet and 1 otherwise indicating that one solution is available.
MOI.get(model::ManoptOptimizer, ::MOI.PrimalStatus)Return MOI.NO_SOLUTION if optimize! hasn't been called yet and MOI.FEASIBLE_POINT if it is otherwise indicating that a solution is available to query with VariablePrimalStart.
MOI.get(::ManoptOptimizer, ::MOI.DualStatus)Returns MOI.NO_SOLUTION indicating that there is no dual solution available.
MOI.get(model::ManoptOptimizer, ::MOI.RawStatusString)Return a String containing get_reason without the ending newline character.
MOI.get(model::ManoptOptimizer, attr::MOI.ObjectiveValue)Return the value of the objective function evaluated at the solution.
MOI.get(model::ManoptOptimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex)Return the value of the solution for the variable of index vi.
MathOptInterface.is_valid β FunctionMOI.is_valid(model::ManoptOptimizer, vi::MOI.VariableIndex)Return whether vi is a valid variable index.
MathOptInterface.supports β FunctionMOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return a Bool indicating whether attr.name is a valid option name for Manopt.
MOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return true indicating that ManoptOptimizer supports starting values for the variables.
MOI.supports(::ManoptOptimizer, ::Union{MOI.ObjectiveSense,MOI.ObjectiveFunction})Return true indicating that Optimizer supports being set the objective sense (that is, min, max or feasibility) and the objective function.
MathOptInterface.supports_incremental_interface β FunctionMOI.supports_incremental_interface(::ManoptOptimizer)Return true indicating that ManoptOptimizer implements add_constrained_variables and set for ObjectiveFunction so it can be used with direct_model and does not require a CachingOptimizer. See See supports_incremental_interface.
MathOptInterface.set β FunctionMOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Set the value for the keyword argument attr.name to give for the constructor model.options[DESCENT_STATE_TYPE].
function MOI.set(
model::ManoptOptimizer,
::MOI.VariablePrimalStart,
vi::MOI.VariableIndex,
value::Union{Real,Nothing},
)Set the starting value of the variable of index vi to value. Note that if value is nothing then it essentially unset any previous starting values set and hence MOI.optimize! unless another starting value is set.
MOI.set(model::ManoptOptimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense)Modify the objective sense to either MAX_SENSE, MIN_SENSE or FEASIBILITY_SENSE.
MOI.set(model::ManoptOptimizer, ::MOI.ObjectiveFunction{F}, func::F) where {F}Set the objective function as func for model.
Internal wrappers and their functions
ManoptJuMPExt.ManifoldPointArrayShape β TypeManifoldPointArrayShape{N} <: JuMP.AbstractShapeRepresent some generic AbstractArray of a certain size representing an point on a manifold
Fields
size::NTuple{N,Int}: The size of the array
ManoptJuMPExt.ManifoldSet β TypeManifoldSet{M<:ManifoldsBase.AbstractManifold} <: MOI.AbstractVectorSetModel a manifold from ManifoldsBase.jl as a vectorial set in the MathOptInterface (MOI). This is a slight misuse of notation, since the manifold itself might not be embedded, but just be parametrized in a certain way.
Fields
manifold::M: The manifold in which the variables are constrained to lie. This is aManifoldsBase.AbstractManifoldobject.
ManoptJuMPExt.ManoptOptimizer β TypeManoptOptimizer <: MOI.AbstractOptimizerRepresent a solver from Manopt.jl within the MathOptInterface (MOI) framework of JuMP.jl
Fields
problem::AbstractManoptProblema problem in manopt, especially containing the manifold and the objective function. It can be constructed as soon as the manifold and the objective are present.manifold::AbstractManifoldthe manifold on which the optimization is performed.objective::AbstractManifoldObjectivethe objective function to be optimized.state::AbstractManoptSolverStatethe state specifying the solver to use.variable_primal_start::Vector{Union{Nothing,Float64}}starting value for the solver, in a vectorized form thatJuMP.jlrequires.sense::MOI.OptimizationSensethe sense of optimization, currently only minimization and maximization are supported.options::Dict{String,Any}: parameters specifying a solver before thestateis initialized, so especially whichAbstractManoptSolverStateto use, when setting up the `state.
All types in brackets can also be Nothing, indicating they were not yet initialized.
ManoptJuMPExt.RiemannianFunction β TypeRiemannianFunction{MO<:Manopt.AbstractManifoldObjective} <: MOI.AbstractScalarFunctionA wrapper for a AbstractManifoldObjective that can be used as a MOI.AbstractScalarFunction.
Fields
func::MO: TheAbstractManifoldObjectivefunction to be wrapped.
ManoptJuMPExt._EmbeddingObjective β Type_EmbeddingObjective{E<:MOI.AbstractNLPEvaluator,T}Objective where evaluator is a MathOptInterface evaluator for the objective in the embedding. The fields vectorized_point, vectorized_tangent and embedding_tangent are used as preallocated buffer so that the conversion to Euclidean objective is allocation-free.
Base.length β Methodlength(shape::ManifoldPointArrayShape)Return the length of the vectors in the vectorized representation.
JuMP.build_variable β MethodJuMP.build_variable(::Function, func, m::ManifoldsBase.AbstractManifold)Build a JuMP.VariablesConstrainedOnCreation object containing variables and the ManifoldSet in which they should belong as well as the shape that can be used to go from the vectorized MOI representation to the shape of the manifold, that is, ManifoldPointArrayShape.
JuMP.jump_function β MethodJuMP.jump_function(::JuMP.AbstractModel, F::Type{<:RiemannianFunction})The JuMP.jl function of a RiemannianFunction for any AbstractModel is that function itself.
JuMP.jump_function_type β MethodJuMP.jump_function_type(::JuMP.AbstractModel, F::Type{<:RiemannianFunction})The JuMP.jl function type of a function of type RiemannianFunction for any AbstractModel is that function type itself
JuMP.reshape_vector β MethodJuMP.reshape_vector(vector::Vector, shape::ManifoldPointArrayShape)Given some vector representation vector used within JuMP of a point on a manifold represents points by arrays, use the information from the shape to reshape it back into such an array. For the inverse see JuMP.vectorize.
JuMP.set_objective_function β MethodJuMP.set_objective_function(model::JuMP.Model, obj::Manopt.AbstractManifoldObjective)Set the objective function of a JuMP.Model model to an AbstractManifoldObjective obj. This allows to use @objective with an objective from Manopt.jl.
JuMP.vectorize β MethodJuMP.vectorize(p::Array{T,N}, shape::ManifoldPointArrayShape{N}) where {T,N}Given a point p as an $N$-dimensional array representing a point on a certain manifold, reshape it to a vector, which is necessary within JuMP. For the inverse see JuMP.reshape_vector.
Manopt.JuMP_Optimizer β MethodManopt.JuMP_Optimizer()Represent a solver from Manopt.jl within the MathOptInterface (MOI) framework. See ManoptOptimizer for the fields and their meaning.
ManoptJuMPExt._get_cost β Method_get_cost(M, objective::_EmbeddingObjective, p)Convert the point p to its vectorization and then evaluate the objective using objective.evaluator.
ManoptJuMPExt._get_gradient! β Method_get_cost(M, objective::_EmbeddingObjective, p)Convert the point p to its vectorization and then evaluate the gradient using objective.evaluator to get the vectorized gradient. Then reshape the gradient and convert it to the Riemannian gradient.
ManoptJuMPExt._reshape_vector! β Method_reshape_vector!(res::Array{T,N}, vec::Vector{T}, ::ManifoldPointArrayShape{N}) where {T,N}Inplace version of res = JuMP.reshape_vector(vec, shape).
ManoptJuMPExt._shape β Method_shape(m::ManifoldsBase.AbstractManifold)Return the shape of points of the manifold m. At the moment, we only support manifolds for which the shape is a Array.
ManoptJuMPExt._vectorize! β Method_vectorize!(res::Vector{T}, array::Array{T,N}, shape::ManifoldPointArrayShape{N}) where {T,N}Inplace version of res = JuMP.vectorize(array, shape).
ManoptJuMPExt._zero β Method_zero(shape::ManifoldPointArrayShape)Return a zero element of the shape shape.
MathOptInterface.Utilities.map_indices β MethodMOI.Utilities.map_indices(index_map::Function, func::RiemannianFunction)The original docstring states something about substituting some variable indices by their index map variants. On a RiemannianFunction there is nothing to substitute,
MathOptInterface.add_constrained_variables β MethodMOI.add_constrained_variables(model::ManoptOptimizer, set::ManifoldSet)Add dimension(set) variables constrained in set and return the list of variable indices that can be used to reference them as well a constraint index for the constraint enforcing the membership of the variables manifold as a set.
MathOptInterface.copy_to β MethodMOI.copy_to(dest::ManoptOptimizer, src::MOI.ModelLike)Because supports_incremental_interface(dest) is true, this simply uses default_copy_to and copies the variables with add_constrained_variables and the objective sense with set.
MathOptInterface.dimension β MethodMOI.dimension(set::ManifoldSet)Return the representation size of points on the (vectorized in representation) manifold. As the MOI variables are real, this means if the representation_size yields (in product) n, this refers to the vectorized point / tangent vector from (a subset of $β^n$).
Note that this is not the dimension of the manifold itself, but the vector length of the vectorized representation of the manifold.
MathOptInterface.empty! β MethodMOI.empty!(model::ManoptOptimizer)Clear all model data from model but keep the options set.
MathOptInterface.get β MethodMOI.get(::ManoptOptimizer, ::MOI.DualStatus)Returns MOI.NO_SOLUTION indicating that there is no dual solution available.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.NumberOfVariables)Return the number of variables added in the model, this corresponds to the dimension of the ManifoldSet.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.ObjectiveSense)Return the objective sense, defaults to FEASIBILITY_SENSE if no sense has already been set.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, attr::MOI.ObjectiveValue)Return the value of the objective function evaluated at the solution.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.PrimalStatus)Return MOI.NO_SOLUTION if optimize! hasn't been called yet and MOI.FEASIBLE_POINT if it is otherwise indicating that a solution is available to query with VariablePrimalStart.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return last value set by set(model, attr, value).
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.RawStatusString)Return a String containing get_reason without the ending newline character.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.ResultCount)Return 0 if optimize! hasn't been called yet and 1 otherwise indicating that one solution is available.
MathOptInterface.get β MethodMOI.get(::ManoptOptimizer, ::MOI.SolverName)Return the name of the ManoptOptimizer with the value of the descent_state_type option.
MathOptInterface.get β MethodMOI.get(::ManoptOptimizer, ::MOI.SolverVersion)Return the version of the Manopt solver, it corresponds to the version of Manopt.jl.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, ::MOI.ResultCount)Return OPTIMIZE_NOT_CALLED if optimize! hasn't been called yet and LOCALLY_SOLVED otherwise indicating that the solver has solved the problem to local optimality the value of RawStatusString for more details on why the solver stopped.
MathOptInterface.get β MethodMOI.get(model::ManoptOptimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex)Return the value of the solution for the variable of index vi.
MathOptInterface.is_valid β MethodMOI.is_valid(model::ManoptOptimizer, vi::MOI.VariableIndex)Return whether vi is a valid variable index.
MathOptInterface.set β MethodMOI.set(model::ManoptOptimizer, ::MOI.ObjectiveFunction{F}, func::F) where {F}Set the objective function as func for model.
MathOptInterface.set β MethodMOI.set(model::ManoptOptimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense)Modify the objective sense to either MAX_SENSE, MIN_SENSE or FEASIBILITY_SENSE.
MathOptInterface.set β MethodMOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Set the value for the keyword argument attr.name to give for the constructor model.options[DESCENT_STATE_TYPE].
MathOptInterface.set β Methodfunction MOI.set(
model::ManoptOptimizer,
::MOI.VariablePrimalStart,
vi::MOI.VariableIndex,
value::Union{Real,Nothing},
)Set the starting value of the variable of index vi to value. Note that if value is nothing then it essentially unset any previous starting values set and hence MOI.optimize! unless another starting value is set.
MathOptInterface.supports β MethodMOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return a Bool indicating whether attr.name is a valid option name for Manopt.
MathOptInterface.supports β MethodMOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)Return true indicating that ManoptOptimizer supports starting values for the variables.
MathOptInterface.supports β MethodMOI.supports(::ManoptOptimizer, ::Union{MOI.ObjectiveSense,MOI.ObjectiveFunction})Return true indicating that Optimizer supports being set the objective sense (that is, min, max or feasibility) and the objective function.
MathOptInterface.supports_add_constrained_variables β MethodMOI.supports_add_constrained_variables(::ManoptOptimizer, ::Type{<:ManifoldSet})Return true indicating that ManoptOptimizer support optimization on variables constrained to belong in a vectorized manifold.
MathOptInterface.supports_incremental_interface β MethodMOI.supports_incremental_interface(::ManoptOptimizer)Return true indicating that ManoptOptimizer implements add_constrained_variables and set for ObjectiveFunction so it can be used with direct_model and does not require a CachingOptimizer. See See supports_incremental_interface.