Computes the Euclidean gradient of the cost function at x. function egrad = getEuclideanGradient(problem, x) function egrad = getEuclideanGradient(problem, x, storedb) function egrad = getEuclideanGradient(problem, x, storedb, key) Returns the Euclidean gradient at x of the cost function described in the problem structure. storedb is a StoreDB object, key is the StoreDB key to point x. Because computing the Hessian based on the Euclidean Hessian will require the Euclidean gradient every time, to avoid overly redundant computations, if the egrad function does not use the store caching capabilites, this implements an automatic caching functionality. Writing egrad to accept the optional store or storedb parameter will disable automatic caching, but allow user controlled caching. See also: getGradient canGetGradient canGetEuclideanGradient
0001 function egrad = getEuclideanGradient(problem, x, storedb, key) 0002 % Computes the Euclidean gradient of the cost function at x. 0003 % 0004 % function egrad = getEuclideanGradient(problem, x) 0005 % function egrad = getEuclideanGradient(problem, x, storedb) 0006 % function egrad = getEuclideanGradient(problem, x, storedb, key) 0007 % 0008 % Returns the Euclidean gradient at x of the cost function described in the 0009 % problem structure. 0010 % 0011 % storedb is a StoreDB object, key is the StoreDB key to point x. 0012 % 0013 % Because computing the Hessian based on the Euclidean Hessian will require 0014 % the Euclidean gradient every time, to avoid overly redundant 0015 % computations, if the egrad function does not use the store caching 0016 % capabilites, this implements an automatic caching functionality. Writing 0017 % egrad to accept the optional store or storedb parameter will disable 0018 % automatic caching, but allow user controlled caching. 0019 % 0020 % See also: getGradient canGetGradient canGetEuclideanGradient 0021 0022 % This file is part of Manopt: www.manopt.org. 0023 % Original author: Nicolas Boumal, July 9, 2013. 0024 % Contributors: 0025 % Change log: 0026 % 0027 % April 3, 2015 (NB): 0028 % Works with the new StoreDB class system. 0029 % 0030 % June 28, 2016 (NB): 0031 % Added support for getPartialEuclideanGradient 0032 % 0033 % July 26, 2018 (NB): 0034 % The Euclidean gradient is now automatically cached if the Euclidean 0035 % Hessian is also computable from the problem description. This 0036 % differs from previous behavior where it would only be cached if 0037 % problem.egrad did not accept store or storedb as input; the 0038 % converse was taken as a sign that the user wants to deal with 0039 % caching on their own, but in reality it proved more confusing than 0040 % helpful. 0041 % 0042 % Sep. 6, 2018 (NB): 0043 % The Euclidean gradient is now always cached. Caching conditioned on 0044 % the Euclidean Hessian being provided was problematic, because if no 0045 % Hessian is provided at all, then the default fall-back of finite 0046 % differences would be slowed down significantly without cache. Since 0047 % the new storedb functionalities around storedb.remove() much reduce 0048 % the number of stored stores, this should not be an issue. 0049 0050 % Allow omission of the key, and even of storedb. 0051 if ~exist('key', 'var') 0052 if ~exist('storedb', 'var') 0053 storedb = StoreDB(); 0054 end 0055 key = storedb.getNewKey(); 0056 end 0057 0058 % Contrary to most similar functions, here, we get the store by 0059 % default. This is for the special caching functionality described 0060 % below. 0061 store = storedb.getWithShared(key); 0062 store_is_stale = false; 0063 0064 % We force caching of the Euclidean gradient. Look up first. 0065 force_egrad_caching = true; 0066 if force_egrad_caching && isfield(store, 'egrad__') 0067 egrad = store.egrad__; 0068 return; 0069 end 0070 0071 if isfield(problem, 'egrad') 0072 %% Compute the Euclidean gradient using egrad. 0073 0074 % Check whether this function wants to deal with storedb or not. 0075 switch nargin(problem.egrad) 0076 case 1 0077 egrad = problem.egrad(x); 0078 case 2 0079 [egrad, store] = problem.egrad(x, store); 0080 case 3 0081 egrad = problem.egrad(x, storedb, key); 0082 % The store structure in storedb might have been modified 0083 % (since it is passed by reference), so before caching 0084 % we'll have to update (see below). 0085 store_is_stale = true; 0086 otherwise 0087 up = MException('manopt:getEuclideanGradient:badegrad', ... 0088 'egrad should accept 1, 2 or 3 inputs.'); 0089 throw(up); 0090 end 0091 0092 elseif canGetPartialEuclideanGradient(problem) 0093 %% Compute the Euclidean gradient using a full partial Euclidean gradient. 0094 0095 d = problem.ncostterms; 0096 egrad = getPartialEuclideanGradient(problem, x, 1:d, storedb, key); 0097 store_is_stale = true; 0098 0099 else 0100 %% Abandon computing the Euclidean gradient 0101 0102 up = MException('manopt:getEuclideanGradient:fail', ... 0103 ['The problem description is not explicit enough to ' ... 0104 'compute the Euclidean gradient of the cost.']); 0105 throw(up); 0106 0107 end 0108 0109 % If we are not sure that the store structure is up to date, update. 0110 if store_is_stale 0111 store = storedb.getWithShared(key); 0112 end 0113 0114 % Cache here. 0115 if force_egrad_caching 0116 store.egrad__ = egrad; 0117 end 0118 0119 storedb.setWithShared(store, key); 0120 0121 end