Home > manopt > core > StoreDB.m

StoreDB

PURPOSE ^

SYNOPSIS ^

This is a script file.

DESCRIPTION ^

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 classdef StoreDB < handle_light
0002 % The StoreDB class is a handle class to manage caching in Manopt.
0003 %
0004 % To create an object, call: storedb = StoreDB();
0005 % Alternatively, call: storedb = StoreDB(storedepth); to instruct
0006 % the database to keep at most storedepth store's in its history.
0007 % (Note that clean up only happens when purge() is called).
0008 %
0009 % The storedb object is passed by reference: when it is passed to a
0010 % function as an input, and that function modifies it, the original
0011 % object is modified.
0012 
0013 % This file is part of Manopt: www.manopt.org.
0014 % Original author: Nicolas Boumal, April 3, 2015.
0015 % Contributors:
0016 % Change log:
0017 
0018 % TODO : protect get/setWithShared calls: limit to one, and forbid access
0019 %        to shared memory while it has not been returned.
0020 %        Do think of the applyStatsFun case : calls a getWithShared, does
0021 %        not need a setWithShared. I think for statsfun there should be a
0022 %        method "forfeitWithShared".
0023     
0024     properties(Access = public)
0025        
0026         % This memory is meant to be shared at all times. Users can modify
0027         % this at will. It is the same for all points x.
0028         shared = struct();
0029         
0030         % This memory is used by the toolbox for, e.g., automatic caching
0031         % and book keeping. Users should not overwrite this. It is the
0032         % same for all points x.
0033         internal = struct();
0034         
0035         % When calling purge(), only a certain number of stores will be
0036         % kept in 'history'. This parameter fixes that number. The most
0037         % recently modified stores are kept. Set to inf to keep all stores.
0038         storedepth = inf;
0039         
0040     end
0041     
0042     properties(Access = private)
0043         
0044         % This structure holds separate memories for individual points.
0045         % Use get and set to interact with this. The field name 'shared' is
0046         % reserved, for use with get/setWithShared.
0047         history = struct();
0048         
0049         % This internal counter is used to obtain unique key's for points.
0050         counter = uint32(0);
0051         
0052         % This internal counter is used to time calls to 'set', and hence
0053         % keep track of which stores in 'history' were last updated.
0054         timer = uint32(0);
0055         
0056     end
0057     
0058     
0059     methods(Access = public)
0060         
0061         % Constructor
0062         function storedb = StoreDB(storedepth)
0063             if nargin >= 1
0064                 storedb.storedepth = storedepth;
0065             end
0066         end
0067         
0068         % Return the store associated to a given key.
0069         % If the key is unknown, returns an empty structure.
0070         function store = get(storedb, key)
0071             if isfield(storedb.history, key)
0072                 store = storedb.history.(key);
0073             else
0074                 store = struct();
0075             end
0076         end
0077         
0078         % Same as get, but adds the shared memory in store.shared.
0079         function store = getWithShared(storedb, key)
0080             store = storedb.get(key);
0081             store.shared = storedb.shared;
0082         end
0083         
0084         % Save the given store at the given key. If no key is provided, a
0085         % new key is generated for this store (i.e., it is assumed this
0086         % store pertains to a new point). The key is returned in all cases.
0087         % A field 'lastset__' is added/updated in the store structure,
0088         % keeping track of the last time that store was modified.
0089         function key = set(storedb, store, key)
0090             if nargin < 3
0091                 key = getNewKey(storedb);
0092             end
0093             store.lastset__ = storedb.timer;
0094             storedb.timer = storedb.timer + 1;
0095             storedb.history.(key) = store;
0096         end
0097         
0098         % Same as set, but extracts the shared memory and saves it.
0099         % The stored store will still have a 'shared' field, but it will be
0100         % empty.
0101         function key = setWithShared(storedb, store, key)
0102             storedb.shared = store.shared;
0103             store.shared = [];
0104             key = storedb.set(store, key);
0105         end
0106         
0107         % Generate a unique key and return it. This should be called
0108         % everytime a new point is generated / stored. Keys are valid field
0109         % names for structures.
0110         function key = getNewKey(storedb)
0111             key = sprintf('z%d', storedb.counter);
0112             storedb.counter = storedb.counter + 1;
0113         end
0114         
0115         % Clear entries in storedb.history to limit memory usage.
0116         function purge(storedb)
0117             
0118             if isinf(storedb.storedepth)
0119                 return;
0120             end
0121             
0122             if storedb.storedepth <= 0
0123                 storedb.history = struct();
0124                 return;
0125             end
0126 
0127             % Get list of field names (keys).
0128             keys = fieldnames(storedb.history);
0129             nkeys = length(keys);
0130 
0131             % If we need to remove some of the elements in the database,
0132             if nkeys > storedb.storedepth
0133 
0134                 % Get the last-set counter of each element:
0135                 % a higher number means it was modified more recently.
0136                 lastset = zeros(nkeys, 1, 'uint32');
0137                 for i = 1 : nkeys
0138                     lastset(i) = storedb.history.(keys{i}).lastset__;
0139                 end
0140 
0141                 % Sort the counters and determine the threshold above which
0142                 % the field needs to be removed.
0143                 sortlastset = sort(lastset, 1, 'descend');
0144                 minlastset = sortlastset(storedb.storedepth);
0145 
0146                 % Remove all fields that are too old.
0147                 storedb.history = rmfield(storedb.history, ...
0148                                                keys(lastset < minlastset));
0149             end
0150             
0151         end % end of purge()
0152         
0153     end
0154     
0155 end

Generated on Sat 12-Nov-2016 14:11:22 by m2html © 2005