function z = bsxfun(op,x,y)
% BSXFUN Binary Singleton Expansion Function for pre-R2007a.
% BSXFUN(OP,X,Y) applies the function OP to the arguments X and Y where
% singleton dimensions of X and Y have been expanded so that X and Y are
% the same size, but this is done without actually copying any data.
%
% OP must be a function handle to a function that computes an
% element-by-element function of its two arguments.
%
% X and Y can be any numeric arrays where non-singleton dimensions in one
% must correspond to the same or unity size in the other. In other
% words, singleton dimensions in one can be expanded to the size of
% the other, otherwise the size of the dimensions must match.
%
% For example, to subtract the mean from each column, you could use
%
% X2 = X - repmat(mean(X),size(X,1),1);
%
% or, using BSXFUN,
%
% X2 = bsxfun(@minus,X,mean(X));
%
% where the single row of mean(x) has been logically expanded to match
% the number of rows in X, but without actually copying any data.
%
% The function, BSXFUN, exists as a built-in function in MATLAB starting
% in version R2007a. This function is for compatibility in versions
% prior to that.
% Version: 1.0, 26 January 2009
% Based on genop.m published 13 March 2006.
% Author: Douglas M. Schwarz
% Email: dmschwarz=ieee*org, dmschwarz=urgrad*rochester*edu
% Real_email = regexprep(Email,{'=','*'},{'@','.'})
% Check number of inputs.
error(nargchk(3,3,nargin))
% Check to see if 'bsxfun' is a builtin function and use it if so.
if exist('bsxfun','builtin')
z = builtin('bsxfun',op,x,y);
return
end
% Check to make sure first argument is a function handle.
if ~isa(op,'function_handle')
error('bsxfun:nonFunctionHandle',...
'First Argument must be a function handle.')
end
% If op is one of these functions and a mex version exists then use it.
try
switch func2str(op)
case 'plus'
z = bsx_plus(x,y);
case 'minus'
z = bsx_minus(x,y);
case 'times'
z = bsx_times(x,y);
case 'power'
z = bsx_power(x,y);
case 'ldivide'
z = bsx_ldivide(x,y);
case 'rdivide'
z = bsx_rdivide(x,y);
case 'eq'
z = bsx_eq(x,y);
case 'ne'
z = bsx_ne(x,y);
case 'lt'
z = bsx_lt(x,y);
case 'gt'
z = bsx_gt(x,y);
case 'le'
z = bsx_le(x,y);
case 'ge'
z = bsx_ge(x,y);
end
return
catch
% Mex version doesn't exist. Issue warning and use general method
% below.
warning('bsxfun:noMexFunctions',['MEX function not found. Build ',...
'it with make_bsx_mex for greater speed.'])
end
% Compute sizes of x and y, possibly extended with ones so they match
% in length.
nd = max(ndims(x),ndims(y));
sx = size(x);
sx(end+1:nd) = 1;
sy = size(y);
sy(end+1:nd) = 1;
dz = sx ~= sy;
dims = find(dz);
num_dims = length(dims);
% Eliminate some simple cases.
if num_dims == 0 || numel(x) == 1 || numel(y) == 1
z = op(x,y);
return
end
% Check for dimensional compatibility of inputs, compute size and class of
% output array and allocate it.
if ~(all(sx(dz) == 1 | sy(dz) == 1))
error('bsxfun:arrayDimensionsMustMatch',['Non-singleton dimensions',...
' of the two input arrays must match each other.'])
end
sz = max([sx;sy]);
z1 = op(x(1),y(1));
if islogical(z1)
z = false(sz);
else
z = zeros(sz,class(z1));
end
% The most efficient way to compute the result seems to require that we
% loop through the unmatching dimensions (those where dz = 1), performing
% the operation and assigning to the appropriately indexed output. Since
% we don't know in advance which or how many dimensions don't match we have
% to create the code as a string and then eval it. To see how this works,
% uncomment the disp statement below to display the code before it is
% evaluated. This could all be done with fixed code using subsref and
% subsasgn, but that way seems to be much slower.
% Compute code strings representing the subscripts of x, y and z.
xsub = subgen(sy ~= sz);
ysub = subgen(sx ~= sz);
zsub = subgen(dz);
% Generate the code.
indent = 2; % spaces per indent level
code_cells = cell(1,2*num_dims + 1);
for i = 1:num_dims
code_cells{i} = sprintf('%*sfor i%d = 1:sz(%d)\n',indent*(i-1),'',...
dims([i i]));
code_cells{end-i+1} = sprintf('%*send\n',indent*(i-1),'');
end
code_cells{num_dims+1} = sprintf('%*sz(%s) = op(x(%s),y(%s));\n',...
indent*num_dims,'',zsub,xsub,ysub);
code = [code_cells{:}];
% Evaluate the code.
% disp(code)
eval(code)
function sub = subgen(select_flag)
elements = {':,','i%d,'};
selected_elements = elements(select_flag + 1);
format_str = [selected_elements{:}];
sub = sprintf(format_str(1:end-1),find(select_flag));