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: ExponentialRetraction()
* 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=ExponentialRetraction(), 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: Yes
In general this defines the following new stepsize
Manopt.LineSearchesStepsize
β TypeLineSearchesStepsize <: Stepsize
Wrapper 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("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 side 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$).
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.AbstractShape
Represent 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.AbstractVectorSet
Model 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.AbstractManifold
object.
ManoptJuMPExt.ManoptOptimizer
β TypeManoptOptimizer <: MOI.AbstractOptimizer
Represent a solver from Manopt.jl
within the MathOptInterface
(MOI) framework of JuMP.jl
Fields
problem::
AbstractManoptProblem
a 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::
AbstractManifold
the manifold on which the optimization is performed.objective::
AbstractManifoldObjective
the objective function to be optimized.state::
AbstractManoptSolverState
the state specifying the solver to use.variable_primal_start::Vector{Union{Nothing,Float64}}
starting value for the solver, in a vectorized form thatJuMP.jl
requires.sense::
MOI.OptimizationSense
the sense of optimization, currently only minimization and maximization are supported.options::Dict{String,Any}
: parameters specifying a solver before thestate
is initialized, so especially whichAbstractManoptSolverState
to 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.AbstractScalarFunction
A wrapper for a AbstractManifoldObjective
that can be used as a MOI.AbstractScalarFunction
.
Fields
func::MO
: TheAbstractManifoldObjective
function to be wrapped.
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.
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 side 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$).
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
.