Returns a manifold structure representing the tangent space to M at x. N = tangentspacefactory(M, x) N defines a (linear) manifold that is the tangent space to M at x. Points are represented as tangent vectors to M at x. Tangent vectors are also represented as tangent vectors to M at x. This is chiefly useful to solve optimization problems involving tangent vectors to M at x, which notably comes up when solving linear systems involving, for example, the Hessian of the cost on M at x (think of the Newton equations.) The Riemannian (actually, Euclidean) structure on N is that of the tangent space to M, that is, the inner product is inherited. See also: preconhessiansolve
0001 function N = tangentspacefactory(M, x) 0002 % Returns a manifold structure representing the tangent space to M at x. 0003 % 0004 % N = tangentspacefactory(M, x) 0005 % 0006 % N defines a (linear) manifold that is the tangent space to M at x. Points 0007 % are represented as tangent vectors to M at x. Tangent vectors are also 0008 % represented as tangent vectors to M at x. 0009 % 0010 % This is chiefly useful to solve optimization problems involving tangent 0011 % vectors to M at x, which notably comes up when solving linear systems 0012 % involving, for example, the Hessian of the cost on M at x (think of the 0013 % Newton equations.) The Riemannian (actually, Euclidean) structure on N is 0014 % that of the tangent space to M, that is, the inner product is inherited. 0015 % 0016 % See also: preconhessiansolve 0017 0018 % This file is part of Manopt: www.manopt.org. 0019 % Original author: Nicolas Boumal, April 9, 2015. 0020 % Contributors: 0021 % Change log: 0022 % 0023 % Jan. 25, 2017 (NB): 0024 % Following a comment by Jesus Briales on the Manopt forum, the 0025 % functions N.egrad2rgrad, N.ehess2rhess and N.tangent now include a 0026 % projection (they were formerly identities.) 0027 % 0028 % Feb. 2, 2017 (NB): 0029 % Following a comment by Jesus Briales on the Manopt forum, the 0030 % function N.proj now calls M.proj(x, .) instead of M.proj(y, .). 0031 % Furthermore, N.ehess2rhess was corrected in the same way. 0032 % 0033 % Dec. 14, 2019 (NB): 0034 % Fixed N.tangent so that it should now work with factories that 0035 % have a non-identity tangent2ambient, e.g., fixedrankembeddedfactory 0036 % and rotationsfactory. 0037 0038 % N is the manifold we build. y will be a point on N, thus also a 0039 % tangent vector to M at x. This is a typical Euclidean space, hence it 0040 % will be easy to describe in terms of the tools available for M. 0041 N = struct(); 0042 0043 % u, u1 and u2 will be tangent vectors to N at y. The tangent space to 0044 % N at y is the tangent space to M at x, thus u, u1 and u2 are also 0045 % tangent vectors to M at x. 0046 0047 if isfield(M, 'name') 0048 N.name = @() ['Tangent space to ' M.name()]; 0049 end 0050 N.dim = @() M.dim(); 0051 N.inner = @(y, u1, u2) M.inner(x, u1, u2); 0052 N.norm = @(y, u) M.norm(x, u); 0053 N.proj = @(y, u) M.proj(x, u); 0054 N.typicaldist = @() sqrt(N.dim()); 0055 if isfield(M, 'tangent2ambient') 0056 N.tangent = @(y, u) M.proj(x, M.tangent2ambient(x, u)); 0057 else 0058 N.tangent = N.proj; 0059 end 0060 0061 N.egrad2rgrad = N.proj; 0062 N.ehess2rhess = @(y, eg, eh, d) M.proj(x, eh); 0063 N.exp = @exponential; 0064 N.retr = @exponential; 0065 N.log = @(y1, y2) M.lincomb(x, 1, y2, -1, y1); 0066 N.pairmean = @(y1, y2) M.lincomb(x, 0.5, y1, 0.5, y2); 0067 N.rand = @() M.randvec(x); 0068 N.randvec = @(y) M.randvec(x); 0069 N.zerovec = M.zerovec; 0070 N.lincomb = M.lincomb; 0071 N.transp = @(y1, y2, u) u; 0072 N.hash = @(y) ['z' hashmd5(M.vec(x, y))]; 0073 0074 % In a Euclidean space, the exponential is merely the sum: y + tu. 0075 function yy = exponential(y, u, t) 0076 if nargin == 2 0077 t = 1; 0078 end 0079 yy = M.lincomb(x, 1, y, t, u); 0080 end 0081 0082 end