Hello,
When working with complex matrices, a common (real) inner product is this one: <A, B> = real(trace(A* B)) where A* is the Hermitian conjugate-transpose of A.
Notice how we take the real part of the trace, so that this inner product is indeed always a real number. (There is a bit more information around equation (3.17) in my
book.)
For your function f(U) = ||UA - B||^2, I assume you mean the Frobenius norm. Then, you can check that f(U) = <UA - B, UA - B> (with the inner product above).
What happens to f(U) if we push U a little bit in the direction V? That is, what the the value of Df(U)[V], the "directional derivative" of f at U along the direction V?
If we apply the chain rule and the product rule (since <., .> is indeed a product), then we find:
Df(U)[V] = <VA, UA - B> + <UA - B, VA>
Notice that the inner product is symmetric, and also that we can move a matrix from one side to the other in the inner product simply by taking its conjugate-transpose (see my book if you're not familiar with that fact); so:
Df(U)[V] = 2 <VA, UA - B> = <V, 2(UA-B)A*>
This show that the Euclidean gradient of f at U with respect to the inner product chosen above is:
nabla f(U) = 2(UA-B)A*
You can check that this is correct with the following Manopt code in Matlab:
problem.M = euclideancomplexfactory(5, 5);
A = randn(5)+1i*randn(5);
B = randn(5)+1i*randn(5);
problem.cost = @(U) norm(U*A-B, 'fro')^2;
problem.egrad = @(U) 2*(U*A-B)*A';
checkgradient(problem);
To get the Riemannian gradient on the unitary group (with the Riemannian submanifold metric, which is typical), it remains to compute the orthogonal projection of the Euclidean gradient to the tangent space.
In Manopt, you could just do this:
problem.M = unitaryfactory(5);
problem.cost = @(U) norm(U*A-B, 'fro')^2;
problem.egrad = @(U) 2*(U*A-B)*A';
checkgradient(problem);
Notice that we changed the manifold (problem.M), but that's it: all the rest is the same. That's because problem.egrad specifies the Euclidean gradient ("egrad", not "grad"), and Manopt takes care of the conversion automatically.
You can also specify the Riemannian gradient (problem.grad) by doing the projection yourself. The projector at U maps a matrix P to the matrix U skew(U* P) where skew(M) = (M-M*)/2 is the skew-Hermitian part of a matrix.
Hope this helps,
Nicolas