Ответ 1
Не изобретайте велосипед - то, что вам нужно, называется "Memoization". МАТЕМАТИКА Google MATLAB, и вы найдете полезные результаты. Некоторые образцы (не проверяли достоверность кода):
У меня довольно тяжелая функция в MATLAB:
function [out] = f ( in1, in2, in3)
Это часто называют одинаковые параметры. Функция детерминирована, поэтому при заданных входных параметрах ее выход всегда будет одинаковым.
Каким будет самый простой способ хранения результатов вычисляемых входов в функции, так что если функция будет вызываться снова с тем же выходом, она сможет быстро ответить?
Является ли постоянная переменная, которая отображает (используя containers.Map
или какой-либо другой класс) набор <in1, in2, in3>
для результата?
Обратите внимание, что любой метод, который требует сохранения данных на диске, в моем приложении не может быть и речи.
Не изобретайте велосипед - то, что вам нужно, называется "Memoization". МАТЕМАТИКА Google MATLAB, и вы найдете полезные результаты. Некоторые образцы (не проверяли достоверность кода):
MATLAB теперь поставляется с функцией только для этой цели. Используемая техника называется "memoization", а имя функции "memoize".
Выезд: https://www.mathworks.com/help/matlab/ref/memoize.html
Ниже приведена идея класса CacheableFunction
Определение класса
classdef CacheableFunction < handle
properties
exeFun
hashFun
cacheMap
nOutputs
zipOutput
end
methods
function obj = CacheableFunction(exeFun, hashFun, nOutputs)
obj.exeFun = exeFun;
obj.hashFun = hashFun;
obj.cacheMap = containers.Map;
obj.nOutputs = nOutputs;
obj.zipOutput = [];
end
function [result] = evaluate(obj, varargin)
thisKey = obj.hashFun(varargin);
if isKey(obj.cacheMap, thisKey)
if obj.zipOutput
result = cellfun(@(x) dunzip(x), obj.cacheMap(thisKey), 'UniformOutput', false);
else
result = obj.cacheMap(thisKey);
end
else
[result{1:obj.nOutputs}] = obj.exeFun(varargin);
if isempty(obj.zipOutput)
obj.zipCheck(result);
end
if obj.zipOutput
obj.cacheMap(thisKey) = cellfun(@(x) dzip(x), result, 'UniformOutput', false);
else
obj.cacheMap(thisKey) = result;
end
end
end
function [] = zipCheck(obj,C)
obj.zipOutput = all(cellfun(@(x) isreal(x) & ~issparse(x) & any(strcmpi(class(x), ...
{'double','single','logical','char','int8','uint8',...
'int16','uint16','int32','uint32','int64','uint64'})), C));
end
end
end
Тестирование этого...
function [] = test_caching_perf()
A = CacheableFunction(@(x) long_annoying_function(x{:}), @(x) DataHash(x), 3);
B = rand(50, 50);
C = rand(50, 50);
D = rand(50, 50);
tic;
myOutput = A.evaluate(B, C, D);
toc
tic;
myOutput2 = A.evaluate(B, C, D);
toc
cellfun(@(x, y) all(x(:) == y(:)), myOutput, myOutput2)
end
function [A, B, C] = long_annoying_function(A, B, C)
for ii = 1:5000000
A = A+1;
B = B+2;
C = C+3;
end
end
И результаты
>> test_caching_perf
Elapsed time is 16.781889 seconds.
Elapsed time is 0.011116 seconds.
ans =
1 1 1
Стойкая карта действительно является хорошим способом реализации кэшированных результатов. Преимущества, о которых я могу думать:
Существует сообщение об обмене файлами, Многомерный класс карты от Дэвида Янга, поставляется с функцией memoize(), делает именно это. В реализации используется бит другой механизм (ссылка на локальную переменную), но идея о том же. По сравнению с постоянной картой внутри каждой функции эта функция memoize() позволяет сохранить существующую функцию без изменений. И, как указал Олег, использование DataHash (или эквивалента) может еще больше сократить использование памяти.
PS: Я широко использовал класс MapN, и он достаточно надежный. На самом деле я представил отчет об ошибке, и автор исправил его быстро.