7

I have a function that takes in more than 2 variables

eg.

testFunction = @(x1, x2, x3, x4) x1.*x2.*x3.*x4;
testFunction2 = @(x1, x2, x3) sin(x1.*x2.^x3);

Is there a function available like bsxfun that allows singleton expansion for functions with more that 2 inputs?

example of bsxfun

binaryTestFunction = @(x1, x2) x1.*x2;
x1 = 9*eye(10);
x2 = 3*ones(10,1);
A = bsxfun(binaryTestFunction , x1 , x2);

Expands the singleton dimension in the x2 vector.
bsxfun is faster than repmat and also highly iterative and hence I want to know if singleton expansion my testFunction is possible.

Daniel
  • 36,610
  • 3
  • 36
  • 69
  • 3
    you can nest several `bsxfun` one inside the other, not the prettiest soluton, but better than nothing... – Shai Mar 30 '15 at 14:52
  • @Shai nesting will require creating multiple testFunctions one for each nest. It will not work in 2 cases: 1. When the nesting functions are implicit _(I have edited the test function to explain what I mean)_. 2. Also I want to treat the function as a blackbox and not touch it. – Ankit Chiplunkar Mar 30 '15 at 15:01

2 Answers2

2

You can define your own class which enables automatic usage of bsxfun:

classdef bdouble < double
    %BDOUBLE double with automatic broadcasting enabled

    methods
        function obj=bdouble(data)
            obj = obj@double(data);
        end
        function r=plus(x,y)
            r=bsxfun(@plus,x,y);
        end
        function r=minus(x,y)
            r=bsxfun(@minus,x,y);
        end
        function r=power(x,y)
            r=bsxfun(@power,x,y);
        end
        function r=times(x,y)
            r=bsxfun(@times,x,y);
        end
        function r=rdivide(x,y)
            r=rdivide(@rdivide,x,y);
        end
        function r=ldivide(x,y)
            r=ldivide(@ldivide,x,y);
        end 
    end
end

Usage:

 testFunction(bdouble([1:3]),bdouble([1:4]'),bdouble(cat(3,1,1)),bdouble(1))

If you prefer bsxfun syntax, you can put this on top:

function varargout=nbsxfun(fun,varargin)
varargout=cell(1:nargout);
for idx=1:numel(varargin)
    if isa(varargin{idx},'double')
        varargin{idx}=bdouble(varargin{idx});
    end
end
varargout{1:max(nargout,1)}=fun(varargin{:});
end

Example:

n=nbsxfun(testFunction,[1:3],[1:4]',cat(3,1,1),4)
Daniel
  • 36,610
  • 3
  • 36
  • 69
1

Just nest functions:

testFunction = @(x1, x2, x3, x4) bsxfun(@times, bsxfun(@times, bsxfun(@times, x1, x2), x3), x4);
testFunction2 = @(x1, x2, x3) sin(bsxfun(@power, bsxfun(@times, x1, x2), x3);

Note that you should implement bsxfun inside the function and not rely on the user calling the function with bsxfun, thus the interaction with the function is seamless regardless.

Note also that there is little speed penalty between using bsxfun when straight element-wise operations could have been used.

There was a file on the file exchange that overides the array operators so that bsxfun was automatically used on all operators, but I cannot remember its name. I used this for a while, but then you run the risk of users not being aware this is implemented.

Wybird666
  • 86
  • 4
  • Note that from Matlab R2016b binary operators automatically perform singleton expansion. This may not be of use to you if you do not have access to the latest version of matlab, but will be to those who do! – Wybird666 Feb 13 '18 at 23:05