Nicky Mattsson
Nicky Mattsson

Reputation: 3052

Avoiding passing large arrays across functions

Consider the following minimal test problem

function [P1,P2,P3] = test()
D = 20;
paths = 1e6;
P1 = zeros(1,paths); P2 = zeros(1,paths); P3 = zeros(1,paths);
G = @(x,flag) A(x,flag);

tic
for i = 1:paths 
   X = randn(1,100);
   P1(i) = G(X,1);
end
t1 = toc;

tic
for i = 1:paths 
   X = 2*randn(1,100);
   P2(i) = G(X,1);
end
t2 = toc;  

tic
a = function(@(x) A(x,0));
for i = 1:paths 
   X = a*randn(1,100);
   P3(i) = G(X,1);
end
t1 = toc;

function [A] = A(x,flag)
A = sum(x);
if flag==1
   A = A/length(x);
end

function [B] = B(x,flag)
B = 0;
for 1:length(x)
   B = (-1)^i * x(i);
if flag==1
   B = B/length(x);
end

So it is a function which runs the either function A or function B on some different data. However my problem is that every time I call either function A or function B I pass a relatively large array (It may be larger than 1x100, I just chose a number) and I do it many times. Note that I do actually need the functions A and B as functions as I need them in the function call (just called "function" here), you may use whatever you like, that is not the interesting part.

Now to the obvious problem, how do I speed this up?

One easy way to do it would be to simply hard code function A and function B into each for loop (in the sense that I copy the code into the for loop and avoid the function handle) and use some if statement to decide which one to go with, then I do not have to pass a matrix that many times. But first of all this is quite ugly and in reality I have many more function than just A and B.

Another way I thought of was to make multiple functions, one for each, but again it quickly becomes ugly as I have many functions and I want to keep the beauty of just having to change the function of interest in the beginning.

So does there exist any way to make this go faster, but still keeping the beauty and ease of just having to change the function of interest one time? I do of course parallelize the for loops, but it doesn't really solve the actual problem.

I have all matlab packages.

Upvotes: 1

Views: 248

Answers (1)

Brethlosze
Brethlosze

Reputation: 1618

I am sorry to tell, but the direct method is the fastest way. The results are consistent while having 1e6 calls. I've excluded the randn calls from each cycle:

Using No Functions at all

Direct Call without Function: 20.38742 sec (1e7 calls)

Using Standard Functions

Standard Function Call: 24.26631 sec (1e7 calls)

Using an Anonymous Handle

Anonymous Function Call: 38.76371 sec (1e7 calls)

Using a Class as Handle

Class as Handle: 211.4325 sec (1e7 calls)

The simpler, the better...

ps. Don't blame my machine. It just, works...

EDIT

Please note, that if you require to pass a function as argument, you can use any of -including but not being limited to- the following options, all of them able to be called as G(x,flag), and all requiring to have the "named" function on the scope:

% Option 1
varfun=@(x,flag) A(x,flag);
G=varfun;

% Option 2
strfun='A(x,flag)';
eval(sprintf('G=@(x,flag) %s;',strfun));

% Option 3
namefun='A';
G=str2func(namefun);

% Option 4
strfun='A(x,flag)';
G=inline(strfun,'x','flag');

% Option 5
keyfun='A';
switch keyfun
    case 'A'
        G=@(x,flag) A(x,flag);
    case 'B'
        G=@(x,flag) B(x,flag);
end

Cheers

Upvotes: 1

Related Questions