Argyll
Argyll

Reputation: 9875

Matlab bsxfun - Why does bsxfun fail to work in this case?

I have a binary function roughly looks like

func=@(i,j)exp(-32*(i-j)^2);

with mesh as follows

[X Y]=meshgrid(-10:.1:10);

Strangely, arrayfun produces the right result while bsxfun would produce entries that are Inf.

an1=arrayfun(func,X,Y);
an2=bsxfun(func,X,Y);

>> max(max(abs(an1-an2)))
ans = 
     Inf

Why?


EDIT: now that the question is resolved. I am including some benchmark data to facilitate the discussion on efficiency with bsxfun

Assuming the grid is already produced with

[X Y]=meshgrid(Grid.partition);
func=@(i,j)exp(-32*(i-j).^2);

(I intend to re-use the grid many times in various places.)

Timing the nested named functions approach.

>> tic;for i=1:1000;temp3=exp(-32*bsxfun(@minus,Grid.partition.',Grid.partition).^2);end;toc,clear temp
Elapsed time is 1.473543 seconds.
>> tic;for i=1:1000;temp3=exp(-32*bsxfun(@minus,Grid.partition.',Grid.partition).^2);end;toc,clear temp
Elapsed time is 1.497116 seconds.
>> tic;for i=1:1000;temp3=exp(-32*bsxfun(@minus,Grid.partition.',Grid.partition).^2);end;toc,clear temp
Elapsed time is 1.816970 seconds.

Timing the anonymous function approach

>> tic;for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear temp
Elapsed time is 1.134980 seconds.
>> tic;for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear temp
Elapsed time is 1.171421 seconds.
>> tic;for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear temp
Elapsed time is 1.180998 seconds.

One can see that the anonymous function approach is faster than the nested function approach (excluding the time on meshgrid).

If the time on meshgrid is included,

>> tic;[X Y]=meshgrid(Grid.partition);for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear X Y temp
Elapsed time is 1.965701 seconds.
>> tic;[X Y]=meshgrid(Grid.partition);for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear X Y temp
Elapsed time is 1.249637 seconds.
>> tic;[X Y]=meshgrid(Grid.partition);for i=1:1000;temp=bsxfun(func,X,Y);end;toc,clear X Y temp
Elapsed time is 1.208296 seconds.

Hard to say...

Upvotes: 4

Views: 224

Answers (2)

Divakar
Divakar

Reputation: 221504

Instead of that way of using Anonymous Functions with bsxfun, you could do something like this for a more efficient usage of bsxfun -

arr1 = -10:.1:10
an2 = exp(-32*bsxfun(@minus,arr1.',arr1).^2)

Benchmarking

Trying to clarify on OP's runtime comments here to compare bsxfun's Anonymous Functions capabilities against the built-in @minus with some benchmarking.

Benchmarking code

func=@(i,j)exp(-32.*(i-j).^2);

num_iter = 1000;

%// Warm up tic/toc.
for k = 1:100000
    tic(); elapsed = toc();
end

disp('---------------------------- Using Anonymous Functions with bsxfun')
tic
for iter = 1:num_iter
    [X Y]=meshgrid(-10:.1:10);
    an2=bsxfun(func,X,Y);
end
toc, clear X Y an2

disp('---------------------------- Using bsxfuns built-in "@minus"')
tic
for iter = 1:num_iter
    arr1 = -10:.1:10;
    an2 = exp(-32*bsxfun(@minus,arr1',arr1).^2);
end
toc

Runtimes

---------------------------- Using Anonymous Functions with bsxfun
Elapsed time is 0.241312 seconds.
---------------------------- Using bsxfuns built-in "@minus"
Elapsed time is 0.221555 seconds.

Upvotes: 3

Luis Mendo
Luis Mendo

Reputation: 112659

Acording to the documentation, when you call bsxfun with an arbitrary function func,

funcmust be able to accept as input either two column vectors of the same size, or one column vector and one scalar, and return as output a column vector of the same size as the input(s).

Your function does not fulfill that. To correct it, replace ^ by .^:

func=@(i,j)exp(-32*(i-j).^2);

Anyway, instead of your function you could use one of bsxfun's built-in functions (see @Divakar's answer). That way you avoid meshgrid, and the code will probably be faster.

Upvotes: 3

Related Questions