# Changing metric for complex sphere in Manopt.jl

**URL:** <https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020>\
**Category:** Optimization (Mathematical)\
**Tags:** manopt\
**Created:** [January 19, 2024, 4:41pm UTC](https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020 "2024-01-19T16:41:11Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![fph](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fph/32/17159_2.png) [@fph](https://discourse.julialang.org/u/fph)\
**Post date:** [January 19, 2024, 4:41pm UTC](https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020/1 "2024-01-19T16:41:11Z")

</div>

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](https://www.manopt.org/reference/manopt/manifolds/sphere/spherecomplexfactory.html) 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`](https://juliamanifolds.github.io/ManoptExamples.jl/stable/objectives/#ManoptExamples.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?

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [January 19, 2024, 7:48pm UTC](https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020/2 "2024-01-19T19:48:32Z")

</div>

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

```Julia
using Manifolds
import Manifolds: inner

struct MyNewMetric <: AbstractMetric end

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

```

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-repl
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)
1.0

```

while

```Julia-repl
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 [SPD](https://juliamanifolds.github.io/Manifolds.jl/stable/manifolds/symmetricpositivedefinite.html)s

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 😉 )

---

<div class="post-metadata">

**Author:** ![fph](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fph/32/17159_2.png) [@fph](https://discourse.julialang.org/u/fph)\
**Post date:** [January 20, 2024, 8:54am UTC](https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020/3 "2024-01-20T08:54:52Z")

</div>

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.

> [@kellertuer](#):
>
> 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.

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.

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [January 20, 2024, 11:48am UTC](https://discourse.julialang.org/t/changing-metric-for-complex-sphere-in-manopt-jl/109020/4 "2024-01-20T11:48:01Z")

</div>

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](https://manoptjl.org/stable/solvers/gradient_descent/#sec-gradient-descent-technical-details). 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 🙂
