It seems be possible to memoize all of the methods in a class at once, rather than the clunky feel of memoizing them one at a time.
This is done by memoizing the each method the first time it is used and storing the result. These function handles are pulled from storage for future uses. To make the interface work, we need to use Matlab's syntax where a method can be called using a string.
The final calling convention looks like this:
%% For a representaive object
>> m = memoizeTest();
%% We can make a bare call to the method
>> m.WorkingMethod([1 2 3])
%% Or make a call to the memoized method, which serves as the interface
>> m.memoized('WorkingMethod', [1 2 3])
Some concerns I would want to test, depending on use, include:
- How does this behave if the method calls try to change the state of the object
- What is the performance hit when using a string for the each method call.
To push this even further, the general purpose memoization can be implemented as a separate class, and then we can use Matlab's multiple inheritance feature to get the same behavior.
Sample code for everything is below.
Sample code #1, adding features to the original class
This code implements memoization of all methods using one property and one method
classdef memoizeTest < handle
methods (Access = public)
%This is the actual, working method we want to memoize
function returnValue = WorkingMethod(self, args)
%Pretend this line is slow :)
returnValue = sum(args);
end
end
%%%% General memoization
% The code below should memoize ALL methods in the class, at the
% cost of a change to the calling syntax. The memoized methods need
% to be called using a string.
properties (Access = private)
%Add a class property to store our memoized methods
memoizedMethods = containers.Map;
end
methods (Access = public)
%Create a public method "memoized" with the following semantics:
%
%For an instance of this class X consider the following cases
% y1 = X.MethodName(inputs)
% y2 = X.memoized('MethodName', inputs)
%y1 and y2 will return the same results, within the limits of the
%"memoize" function.
function out = memoized(self, strMethod, args)
if ismember(strMethod, methods(self))
%For the first call with a particular method, create and
%memoize a function handle view of the method
if ~self.memoizedMethods.isKey(strMethod)
fn_method = @(varargin)self.(strMethod)(varargin{:});
fn = memoize(fn_method);
self.memoizedMethods(strMethod) = fn;
end
%For all calls, get the store function handle out of
%storage, and use it.
fn = self.memoizedMethods(strMethod);
out = fn(args);
else
error(['No appropriate method, property ''' strMethod ''''])
end
end
end
end
Sample code #2, using multiple inheritance
The original code now requires very little adjustment
classdef memoizeTest < handle & Memoizable
methods (Access = public)
%This is the actual, working method we want to memoize
function returnValue = WorkingMethod(self, args)
%Pretend this line is slow :)
returnValue = sum(args);
end
end
end
The Memoizable
class looks like this
classdef Memoizable < handle
%%%% General memoization
% The code below should memoize ALL methods in the class, at the
% cost of a change to the calling syntax. The memoized methods need
% to be called using a string.
properties (Access = private)
%Add a class property to store our memoized methods
memoizedMethods = containers.Map;
end
methods (Access = public)
%Create a public method "memoized" with the following semantics:
%
%For an instance of this class X consider the following cases
% y1 = X.MethodName(inputs)
% y2 = X.memoized('MethodName', inputs)
%y1 and y2 will return the same results, within the limits of the
%"memoize" function.
function out = memoized(self, strMethod, args)
if ismember(strMethod, methods(self))
%For the first call with a particular method, create and
%memoize a function handle view of the method
if ~self.memoizedMethods.isKey(strMethod)
fn_method = @(varargin)self.(strMethod)(varargin{:});
fn = memoize(fn_method);
self.memoizedMethods(strMethod) = fn;
end
%For all calls, get the store function handle out of
%storage, and use it.
fn = self.memoizedMethods(strMethod);
out = fn(args);
else
error(['No method ''' strMethod ''' found'])
end
end
end
end