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 β€” Type
LineSearchesStepsize <: 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

source

Manifolds.jl

Loading Manifolds.jl introduces the following additional functions

Manopt.max_stepsize β€” Method
max_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

source
Manopt.max_stepsize β€” Method
max_stepsize(M::Hyperrectangle, p)

The default maximum stepsize for Hyperrectangle manifold with corners is maximum of distances from p to each boundary.

source
Manopt.max_stepsize β€” Method
max_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.

source
ManifoldsBase.mid_point β€” Function
mid_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).

source

Internally, Manopt.jl provides the two additional functions to choose some Euclidean space when needed as

Manopt.Rn β€” Function
Rn(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

source
Manopt.Rn_default β€” Function
Rn_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.

source

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:

Internal functions

JuMP.build_variable β€” Function
JuMP.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.

source
MathOptInterface.add_constrained_variables β€” Function
MOI.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.

source
MathOptInterface.dimension β€” Function
MOI.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$).

source
MathOptInterface.get β€” Function
MOI.get(::ManoptOptimizer, ::MOI.SolverVersion)

Return the version of the Manopt solver, it corresponds to the version of Manopt.jl.

source
MOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)

Return last value set by set(model, attr, value).

source
MOI.get(::ManoptOptimizer, ::MOI.SolverName)

Return the name of the ManoptOptimizer with the value of the descent_state_type option.

source
MOI.get(model::ManoptOptimizer, ::MOI.NumberOfVariables)

Return the number of variables added in the model, this corresponds to the dimension of the ManifoldSet.

source
MOI.get(model::ManoptOptimizer, ::MOI.ObjectiveSense)

Return the objective sense, defaults to FEASIBILITY_SENSE if no sense has already been set.

source
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.

source
MOI.get(model::ManoptOptimizer, ::MOI.ResultCount)

Return 0 if optimize! hasn't been called yet and 1 otherwise indicating that one solution is available.

source
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.

source
MOI.get(::ManoptOptimizer, ::MOI.DualStatus)

Returns MOI.NO_SOLUTION indicating that there is no dual solution available.

source
MOI.get(model::ManoptOptimizer, ::MOI.RawStatusString)

Return a String containing get_reason without the ending newline character.

source
MOI.get(model::ManoptOptimizer, attr::MOI.ObjectiveValue)

Return the value of the objective function evaluated at the solution.

source
MOI.get(model::ManoptOptimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex)

Return the value of the solution for the variable of index vi.

source
MathOptInterface.supports β€” Function
MOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)

Return a Bool indicating whether attr.name is a valid option name for Manopt.

source
MOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)

Return true indicating that ManoptOptimizer supports starting values for the variables.

source
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.

source
MathOptInterface.set β€” Function
MOI.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].

source
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.

source
MOI.set(model::ManoptOptimizer, ::MOI.ObjectiveSense, sense::MOI.OptimizationSense)

Modify the objective sense to either MAX_SENSE, MIN_SENSE or FEASIBILITY_SENSE.

source
MOI.set(model::ManoptOptimizer, ::MOI.ObjectiveFunction{F}, func::F) where {F}

Set the objective function as func for model.

source

Internal wrappers and their functions

ManoptJuMPExt.ManifoldPointArrayShape β€” Type
ManifoldPointArrayShape{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
source
ManoptJuMPExt.ManoptOptimizer β€” Type
ManoptOptimizer <: 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 that JuMP.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 the state is initialized, so especially which AbstractManoptSolverState to use, when setting up the `state.

All types in brackets can also be Nothing, indicating they were not yet initialized.

source
JuMP.build_variable β€” Method
JuMP.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.

source
JuMP.reshape_vector β€” Method
JuMP.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.

source
JuMP.vectorize β€” Method
JuMP.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.

source
MathOptInterface.add_constrained_variables β€” Method
MOI.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.

source
MathOptInterface.dimension β€” Method
MOI.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$).

source
MathOptInterface.get β€” Method
MOI.get(model::ManoptOptimizer, attr::MOI.ObjectiveValue)

Return the value of the objective function evaluated at the solution.

source
MathOptInterface.get β€” Method
MOI.get(model::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)

Return last value set by set(model, attr, value).

source
MathOptInterface.get β€” Method
MOI.get(model::ManoptOptimizer, ::MOI.ResultCount)

Return 0 if optimize! hasn't been called yet and 1 otherwise indicating that one solution is available.

source
MathOptInterface.get β€” Method
MOI.get(::ManoptOptimizer, ::MOI.SolverVersion)

Return the version of the Manopt solver, it corresponds to the version of Manopt.jl.

source
MathOptInterface.get β€” Method
MOI.get(model::ManoptOptimizer, attr::MOI.VariablePrimal, vi::MOI.VariableIndex)

Return the value of the solution for the variable of index vi.

source
MathOptInterface.set β€” Method
MOI.set(model::ManoptOptimizer, ::MOI.ObjectiveFunction{F}, func::F) where {F}

Set the objective function as func for model.

source
MathOptInterface.set β€” Method
MOI.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].

source
MathOptInterface.set β€” Method
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.

source
MathOptInterface.supports β€” Method
MOI.supports(::ManoptOptimizer, attr::MOI.RawOptimizerAttribute)

Return a Bool indicating whether attr.name is a valid option name for Manopt.

source
MathOptInterface.supports β€” Method
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.

source