Changing metric for complex sphere in Manopt.jl

A technical question on Manopt.jl. I have seen that Sphere(n-1, ℂ) gets its Hermitian metric \langle v, w\rangle_p = v^*w from its canonical embedding in \mathbb{C}^n. Instead, I would like to use that manifold with the metric \langle v, w\rangle_p = \operatorname{Re} (v^*w), which comes from its canonical embedding in \mathbb{R}^{2n}.

(Note that also Manopt for Matlab uses this second metric for the complex sphere.)

Is there a way to change metric easily? I see two avenues, both with disadvantages:

  1. Work with Sphere(2n-1, ℝ), and wrap my function into a wrapper that converts every vector in \mathbb{C}^n in \mathbb{R}^{2n}. This looks cumbersome, and most importantly it changes the working manifold nontrivially, since now v and 1im * v are no longer the same point.

  2. Define a new AbstractMetric from scratch; I see that there is an example of how to define one in RosenbrockMetric in ManoptExamples.jl, but it doesn’t look trivial: I would have to define many new methods, and I am afraid of breaking something subtle down the line. Also, if I understand correctly now I have an AbstractManifold{ℝ} rather than an AbstractManifold{ℂ} and hence I cannot even reuse Sphere(n-1, ℂ) but I have to basically define a new manifold from scratch.

Am I missing a simpler way to do this?

1 Like

Cool that you are using Manopt.jl and Manifolds.jl!

I would recommend the second approach. The idea is the following:

You define a new metric type. All non-metric functions will be unaffected by that. Only “metric-related” functions have to be redone. I mean – the exponential map for example does change so we can not keep it.

I do not understand your last part about the abstract manifold part, the
Sphere(n-1, ℂ) is a AbstractSphere{ℂ} and hence a AbstractManifold{ℂ}. There is no need for a complete new manifold. The field type parameter of the manifold is meant to tell the “element type” of the matrices/vectors used. That is in your case.

To sketch the idea with the new metric, it would look like

using Manifolds
import Manifolds: inner

struct MyNewMetric <: AbstractMetric end

function inner(::MetricManifold{ℂ,<:AbstractSphere{ℂ}, MyNewMetric}, p, X, Y
  return real(X'*Y)

This works like a “wrapper” as you can see in the type of the first argument. To use your new metric you use e.g.

julia> M = MetricManifold(Sphere(2,ℂ), MyNewMetric())
julia> p = [1.0im, 0.0]; X = [1.0im, 0.0]; Y = [1.0im, 0.0]

2-element Vector{ComplexF64}:
 0.0 + 1.0im
 0.0 + 0.0im

julia> inner(M,p,X,Y)


julia> inner(Sphere(2,ℂ),p,X,Y)
1.0 + 0.0im

so we can see, the function we defined above was used. The best manifold to get inspired by, since it uses this a lot is the SPDs

as you manifold. Again, all metric-unrelated functions still work the same as for the sphere (checking points/vectors, dimension,…). Again, exp/log you have to reimplement the same way as inner – but (I hope to remember that correctly) retractions should still work.

Since Manopt uses this metric as well, we could also provide this metric in Manifolds.jl for you. But to be honest – I currently have 4 open PRs, about 6 planned, 2 lecture every week, and 4 students I am supervising.
So I would probably only be available to do that for you, maybe end of February? But feel free to already open an issue to get that with Manifolds.jl.

edit: I think if/when we add it to Manifolds.jl then probably more like an EmbeddedManifold – that works similar to the metric one above, just specifying different embeddings; since the metric is here inherited from the embedding, we would not need a new metric name, so that is a bit nicer to use later. I’ll keep that in the list of things to think about when time (changes the 6 above to a 7 :wink: )


Thanks for the guidance (and for all your work on this package)! This is useful information.

Of course I wasn’t expecting you developers to do the work for me; I’ll do the coding I need; I am grateful for these suggestions. I could even share what I write eventually, but I’m afraid my code might be subpar.

Thanks for the clarification, I had misunderstood this. My understanding was that I need to use \mathbb{R} because I am working with the tangent as if it were a \mathbb{R}-vector space, even if the representers for points and vectors have complex entries. For instance, that second inner product I suggested is \mathbb{R}-linear but not Hermitian, as e.g. \langle X, i Y\rangle_p \neq i \langle X, Y \rangle_p. I need to think this through more though; probably I don’t need \mathbb{C}-linearity anywhere.

1 Like

Thanks for your kind response. I value such feedback a lot, since your misunderstanding is maybe also a sign we can improve our docs somewhere.

On the other hand you might also find inconsitencies - we hope the design is safe and sound, but I personally for example to not use complex manifolds so much.

If you have implemented a manifold – as a decorator (metric or embedded) or a whole new manifold – we would always be interested in bringing that into the package and are super happy to help.
You can – by the way – also go for the whole manifold, and just focus on the functions mentioned in the technical Details section of a solver, like here for gradient descent. This is exactly meant, so you “just” have to implement the manifold-functions, your solver would use.

But I’ll also keep the C-spjere in 2n-R in mind as something I can add when I find time :slight_smile: