Hello Leo,
This is an interesting set -- had not seen this one before.
Just to make sure I got this correctly: (in Matlab notation), we're considering the set of complex matrices S of size n-by-n such that S'*S = eye(n) (unitary) and S.' = S (so, both real(S) and imag(S) are symmetric).
Do we know for sure this is a smooth manifold, embedded in C^{n \times n}?
If I split S = A + i B where A, B are real matrices of size n-by-n, then S'*S = A'*A + B'*A + i ( A'*B - B'*A ), which is identity (that is, S is unitary) iff A'*A + B'*B = eye(n), and A'*B = B'*A.
Then also requiring S.' = S effectively forces A = A' and B = B' (both real symmetric), so the complete list of requirements becomes:
- A = A'
- B = B'
- A'*A + B'*B = eye(n)
- AB = BA
The last one says that A and B commute. Since they are symmetric matrices, this means that A and B can be diagonalized by a common orthogonal matrix of eigenvectors: let's call it V.
Thus, A = VDV' and B = VEV', where D and E are two real, diagonal matrices, and V is a real, orthogonal matrix. The only other condition is that D² + E² = I, which effectively means that
D = diag(cos(theta_1), ..., cos(theta_n)) and E = diag(sin(theta_1), ..., sin(theta_n)).
Overall, it seems to me that your set can be smoothly parameterized by taking n points on a circle (the angles theta_1, ..., theta_n) and a real, orthogonal matrix V, then forming A and B as above and assembling them to form S.
In Manopt, this might go as follows, using a product manifold:
elems.angles = obliquefactory(2, n); % could also use complexcirclefactory(n) if you're comfortable with mixing complex numbers in there
elems.basis = rotationsfactory(n); % could also write stiefelfactory(n, n) if you run into issues related to representation of tangent vectors
manifold = productmanifold(elems);
X = manifold.rand();
S = X.basis*diag(X.angles(1, :) + 1i*X.angles(2, :))*X.basis'; % if using complexcirclefactory, here we'd just take diag()
This indeed generates a random matrix S, and we have a smooth parameterization for that set. You could write a cost function f(S) as a function g(angles, basis) = f(S) (with the change of variables shown above), and get the graident/Hessian using manoptAD (auto-diff) or working it out by hand. This would work.
Or you could implement a factory for that set of S directly, as you started doing above. There, it's indeed important to makes sure the retraction is correct. Even before doing so, one would want to make sure that the set of S is indeed smooth (the above is a smooth parameterization, but that does not imply the set itself is smooth). It very well may be, but it's not immediately obvious to me.
Best,
Nicolas