Computes the cost function at x. function cost = getCost(problem, x) function cost = getCost(problem, x, storedb) function cost = getCost(problem, x, storedb, key) Returns the value at x of the cost function described in the problem structure. storedb is a StoreDB object, key is the StoreDB key to point x. See also: canGetCost
0001 function cost = getCost(problem, x, storedb, key) 0002 % Computes the cost function at x. 0003 % 0004 % function cost = getCost(problem, x) 0005 % function cost = getCost(problem, x, storedb) 0006 % function cost = getCost(problem, x, storedb, key) 0007 % 0008 % Returns the value at x of the cost function described in the problem 0009 % structure. 0010 % 0011 % storedb is a StoreDB object, key is the StoreDB key to point x. 0012 % 0013 % See also: canGetCost 0014 0015 % This file is part of Manopt: www.manopt.org. 0016 % Original author: Nicolas Boumal, Dec. 30, 2012. 0017 % Contributors: 0018 % Change log: 0019 % 0020 % April 3, 2015 (NB): 0021 % Works with the new StoreDB class system. 0022 % 0023 % Aug. 2, 2018 (NB): 0024 % The value of the cost function is now always cached. 0025 % 0026 % Sep. 6, 2018 (NB): 0027 % If the gradient is computed too (because we had to call costgrad 0028 % with the store as input as per the user's request), then the 0029 % gradient is also cached. 0030 0031 % Allow omission of the key, and even of storedb. 0032 if ~exist('key', 'var') 0033 if ~exist('storedb', 'var') 0034 storedb = StoreDB(); 0035 end 0036 key = storedb.getNewKey(); 0037 end 0038 0039 0040 % Contrary to most similar functions, here, we get the store by 0041 % default. This is for the caching functionality described below. 0042 store = storedb.getWithShared(key); 0043 store_is_stale = false; 0044 0045 % If the cost function has been computed before at this point (and its 0046 % memory is still in storedb), then we just look up the value. 0047 if isfield(store, 'cost__') 0048 cost = store.cost__; 0049 return; 0050 end 0051 0052 0053 if isfield(problem, 'cost') 0054 %% Compute the cost function using cost. 0055 0056 % Check whether this function wants to deal with storedb or not. 0057 switch nargin(problem.cost) 0058 case 1 0059 cost = problem.cost(x); 0060 case 2 0061 [cost, store] = problem.cost(x, store); 0062 case 3 0063 % Pass along the whole storedb (by reference), with key. 0064 cost = problem.cost(x, storedb, key); 0065 % The store structure in storedb might have been modified 0066 % (since it is passed by reference), so before caching 0067 % we'll have to update (see below). 0068 store_is_stale = true; 0069 otherwise 0070 up = MException('manopt:getCost:badcost', ... 0071 'cost should accept 1, 2 or 3 inputs.'); 0072 throw(up); 0073 end 0074 0075 elseif isfield(problem, 'costgrad') 0076 %% Compute the cost function using costgrad. 0077 0078 % Check whether this function wants to deal with storedb or not. 0079 switch nargin(problem.costgrad) 0080 case 1 0081 cost = problem.costgrad(x); 0082 case 2 0083 [cost, grad, store] = problem.costgrad(x, store); 0084 case 3 0085 % Pass along the whole storedb (by reference), with key. 0086 cost = problem.costgrad(x, storedb, key); 0087 store_is_stale = true; 0088 otherwise 0089 up = MException('manopt:getCost:badcostgrad', ... 0090 'costgrad should accept 1, 2 or 3 inputs.'); 0091 throw(up); 0092 end 0093 0094 else 0095 %% Abandon computing the cost function. 0096 0097 up = MException('manopt:getCost:fail', ... 0098 ['The problem description is not explicit enough to ' ... 0099 'compute the cost.']); 0100 throw(up); 0101 0102 end 0103 0104 % If we are not sure that the store structure is up to date, update. 0105 if store_is_stale 0106 store = storedb.getWithShared(key); 0107 end 0108 0109 % Cache here. 0110 store.cost__ = cost; 0111 0112 % If we got the cost via costgrad and it took the store as input, then 0113 % the gradient has also been computed and we can cache it. 0114 if exist('grad', 'var') 0115 store.grad__ = grad; 0116 end 0117 0118 storedb.setWithShared(store, key); 0119 0120 end