Applying a function on array that returns outputs with different size in a vectorized manner - matlab

How to apply a function that returns non scalar output to arrays using arrayfun?
For example - How to vectorize the following code?
array = magic(5);
A = cell(size(array));
for i=1:5
for j=1:5
A{i,j} = 1:array(i,j);
end
end
This naive attempt to vectorize does not work, because the output is not a scalar
array = magic(5);
result = arrayfun(#(x)(1:x),array);

There are 2 methods to achieve it:
It is possible to set 'UniformOutput' to false. Then, the result is a cell array.
result = arrayfun(#(x)(1:x),array,'UniformOutput',false);
But there is a nice trick that I have found today, the function itself can return a cell. This removes the need of typing 'UniformOutput',false each and every time.
result = arrayfun(#(x){1:x},array)
What is really interesting here that I don't have to type #(X)({1:x}) but I can define it only by using curly bracers #(X){1:x}
Edit(1): As #Jonas correctly points out, there is no wonder that the regular bracers () are not needed, as they are optional. For example, #(x) x+1 is a valid syntax.
Edit(2): There is a small difference between using the curly bracers method or the UniformOutput,false. When the input array is empty, their behavior is different.

In addition to the answer of Andrey I want to note that it seems, that the first approach, using the option UniformOutput, is slightly faster:
>> tic; cellfun(#(x) {single(x)}, data); toc;
Elapsed time is 0.031817 seconds.
>> tic; cellfun(#(x) single(x), data,'UniformOutput',0); toc;
Elapsed time is 0.025526 seconds.

Related

Create array with function and size

Recently I wrote this statement
v = arrayfun(#(x) sum(randn(1, 4).^2), zeros(1, 1000000));
to create a new vector and now I'm asking if there exists a function in Matlab to avoid the creation of the unnecessary second vector zeros(1, 1000000). I'm looking for something like
v = FUN(#someInitFunction, [rows, cols]);
without loops, recursion and unnecessary allocation where someInitFunction is given and can't be changed. Does Matlab provide such a function FUN? A simple "No, it doesn't exist" would be a valid answer for me.
To summarize the function FUN: I want to create a new array by calling a function someInitFunction for each element of this new array. The array should be equivalent to
[
someInitFunction() someInitFunction() ...;
someInitFunction() someInitFunction() ...;
.
.
.
someInitFunction() someInitFunction() ...
]
As far as I know there is no builtin function for that. It's relatively easy to create your own however.
You asked a solution without loop but the current solution you are using (arrayfun) uses loop under the hood, and generally coding the same in a properly organised loop is actually faster than arrayfun.
For your case, the function GenArrayFun.m :
function out = GenArrayFun(initFunction , arraySize)
out = zeros(arraySize) ;
for k=1:numel(out)
out(k) = initFunction() ;
end
It has a loop, but no more than arrayfun, and seem to perform twice as fast (at least on my installation, R2016a, win10):
initFunction = #() sum(randn(1, 4).^2) ;
tic
v = arrayfun(#(x) sum(randn(1, 4).^2), zeros(1, 1000000));
toc
tic
out = GenArrayFun( initFunction , [1,1000000] );
toc
Sorry I did not take the time to build a proper timeit benchmark for such a small example, I think the results are significant enough to notice a difference:
Elapsed time is 6.815043 seconds. % arrayfun
Elapsed time is 3.060161 seconds. % GenArrayFun
And just to make sure it evaluate the initFunction for every element:
>> out = GenArrayFun( initFunction , [2,3] )
out =
6.25676106665387 6.52758807745462 2.99236122767462
0.386750258201569 0.566092999842791 2.21158011908878

make iterative variable a cell array in matlab

In matlab, is it possible to make the iterative variable a cell array? is there a workaround? This is the code I ideally want, but throws errors:
dim={};
a=magic(5);
for dim{1}=1:5
for dim{2}=1:5
a(dim{:})=1; %aimed to be equivalent to a(dim{1},dim{2})=1;
end
end
for dim{1}=1:5
↑
Error: Invalid expression. When calling a function or indexing a variable, use
parentheses. Otherwise, check for mismatched delimiters.
I tested that you cannot have A(1), or A{1} or A.x as index variable. https://www.mathworks.com/help/matlab/ref/for.html doesn't explicitly prohibit that, but it doesn't allow it either.
After very slight changes on your code, this should achieve what you seem to want:
dim={};
a = magic(5);
for dim1=1:5
dim{1} = dim1;
for dim2=1:5
dim{2} = dim2;
a(dim{:})=1; %aimed to be equivalent to a(dim{1},dim{2})=1;
end
end
However, I believe the following is a slightly better solution keeping the spirit of "use a cell array to index in your array":
CV = combvec(1:5,1:5); % get all combinations from (1,1) to (5,5). 2x25 double array. This function is a part of deep learning toolbox. Alternatives are available.
CM = num2cell(CV); % 2x25 cell array. Each element is a single number.
for dim = CM
% dim is a 2x1 cell array, eg {2,3}.
a(dim{:}) = 1; % as above.
end
However, none of these are likely a good solution to the underlying problem.

MATLAB Return value of first non-empty argument (built-in COALESCE function)

Is there something inbuilt in MATLAB which functions similar to the SQL COALESCE function. I want that function to return the first 'existing' value from all the arguments.
For example,
clear A B; C=10; COALESCE(A,B,C)
should return value of C (because A and B are unassigned/don't exist).
I know it would be very easy to code, and I am just being lazy here. But, I would be surprised if MATLAB doesn't have a similar function.
As far as I know there is no built-in function for that. But you can easily write your own.
Note that it is not possible in Matlab to pass a variable that has not been defined prior of using it. Therefore your proposed call clear A B; C=10; COALESCE(A,B,C) is invalid and will throw an error. Instead we can define an empty variable using var=[].
The following code creates two empty variables A, B and and assigns C=10. Inside the function coalesce we assume at the beginning that all variables are empty. In the for-loop we return the first non-empty variable. In the version without for-loop we get the index of the first non-zero element and then return the corresponding content of the cell if a non-zero element exists.
If you want the function to be accessible from everywhere within Matlab, see the documentation here.
function testcoalesce
A = [];
B = [];
C = 10;
COALESCE(A,B)
COALESCE(A,B,C)
end
% with for-loop (much faster)
function out = COALESCE(varargin)
out = [];
for i = 1:length(varargin)
if ~isempty(varargin{i})
out = varargin{i};
return;
end
end
end
% without for-loop (slower)
function out = COALESCE(varargin)
out = [];
ind = find(cellfun('isempty', varargin)==0, 1);
if ~isempty(ind);
out = varargin{ind};
end
end
The output is as expected:
ans =
[]
ans =
10
Timing the two functions showed, that the first solution using the for-loop is approximately 48% faster than the function without loop.
(10 samples, 1'000'000 iterations, 3 variables & 20 variables)

How to manipulate and assign parts of a MATLAB field - Comma-separated list assignment

Consider the following MATLAB struct:
a(1).num=1; a(2).num=2; a(3).num=3;
The thing I want to do is to replace some of the elements of num with the old value minus a (scalar) number. For example, I would like to subtract 1 from a(2).num and a(3).num.
I already tried different ways:
a(2:3).num=a(2:3).num-1;
??? Error using ==> minus Too many input arguments.
Next try:
>>a(2:3).num=[a(2:3).num]-1;
??? Insufficient outputs from right hand side to satisfy comma separated list
expansion on left hand side. Missing [] are the most likely cause.
And last:
>> [a(2:3).num]=[a(2:3).num]-1;
??? Error using ==> minus
Too many output arguments.
arrayfun couldn´t help either.
Probably there is a quite easy answer to this question, but I couldn´t find any.
Easiest is a two-line solution:
C = num2cell([a(2:3).num]-1);
[a(2:3).num] = C{:}
Nicest is to have a function like deal, but with a function applied to each argument:
function varargout = fcnDeal(varargin)
%// (Copied from MATLAB's deal()
if nargin==1,
varargout = varargin(ones(1,nargout));
else
if nargout ~= nargin-1
error('fcnDeal:narginNargoutMismatch',...
'The number of outputs should match the number of inputs.')
end
%//...Except this part
varargout = cellfun(varargin{1}, varargin(2:end), 'UniformOutput', false);
end
end
Then what you want to do is just a matter of
[a(2:3).num] = fcnDeal(#(x)x-1, a(2:3).num)
You can manipulate them in the loop
index = [1,2]
for i = index
a(i).num = a(i).num - 1;
end

How to elegantly ignore some return values of a MATLAB function

Is it possible to get the 'nth' return value from a function without having to create dummy variables for all n-1 return values before it?
Let's say, I have the following function in MATLAB:
function [a,b,c,d] = func()
a = 1;
b = 2;
c = 3;
d = 4;
Now suppose, I'm only interested in the third return value. This can be accomplished by creating one dummy variable:
[dummy, dummy, variableThatIWillUse, dummy] = func;
clear dummy;
But I think this is kind of ugly. I would think that you might be able to do something like one of the following things, but you can't:
[_, _, variableThatIWillUse, _] = func;
[, , variableThatIWillUse, ] = func;
variableThatIWillUse = func(3);
variableThatIWillUse = func()(3);
Are there any elegant ways to do this that do work?
So far, the best solution is to simply use the variableThatIWillUse as a dummy variable. This saves me from having to create a real dummy variable that pollutes the work-space (or that I would need to clear). In short: the solution is to use the variableThatIWillUse for every return value up until the interesting one. Return values after can simply be ignored:
[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;
I still think this is very ugly code.
With MATLAB Version 7.9 (R2009b) you can use a ~, e.g.,
[~, ~, variableThatIWillUse] = myFunction();
Note that the , isn't optional. Just typing [~ ~ var] will not work, and will throw an error.
See the release notes for details.
This is somewhat of a hack, but it works:
First a quick example function:
Func3 = #() deal(1,2,3);
[a,b,c]=Func3();
% yields a=1, b=2, c=3
Now the key here is that if you use a variable twice on the left-hand side of a multiple-expression assignment, an earlier assignment is clobbered by the later assignment:
[b,b,c]=Func3();
% yields b=2, c=3
[c,c,c]=Func3();
% yields c=3
(Just to check, I also verified that this technique works with [mu,mu,mu]=polyfit(x,y,n) if all you care about from polyfit is the third argument.)
There's a better approach; see ManWithSleeve's answer instead.
If you wish to use a style where a variable will be left to fall into the bit bucket, then a reasonable alternative is
[ans, ans, variableThatIWillUse] = myfun(inputs);
ans is of course the default junk variable for MATLAB, getting overwritten often in the course of a session.
While I do like the new trick that MATLAB now allows, using a ~ to designate an ignored return variable, this is a problem for backwards compatibility, in that users of older releases will be unable to use your code.
I generally avoid using new things like that until at least a few MATLAB releases have been issued to ensure there will be very few users left in the lurch. For example, even now I find people are still using an old enough MATLAB release that they cannot use anonymous functions.
Here's another option you can use. First make a cell array to capture all the outputs (you can use the NARGOUT function to determine how many outputs a given function returns):
a = cell(1,3); % For capturing 3 outputs
% OR...
a = cell(1,nargout(#func)); % For capturing all outputs from "func"
Then call the function as follows:
[a{:}] = func();
Then simply remove the element from a that you want, and overwrite a:
a = a{3}; % Get the third output
I wrote a kth out function:
function kth = kthout(k, ffnc, varargin)
% kthout: take the kth varargout from a func call %FOLDUP
%
% kth = kthout(k, ffnc, varargin)
%
% input:
% k which varargout to get
% ffnc function to call;
% varargin passed to ffnc;
% output:
% kth the kth argout;
[outargs{1:k}] = feval(ffnc, varargin{:});
kth = outargs{k};
end %function
You can then call
val_i_want = kthout(3, #myfunc, func_input_1, func_input_2);
You could also wrap up the function like:
func_i_want = #(varargin)(kthout(3, #myfunc,varargin{:})); % Assuming you want the third output.
After which you use
val_i_want = func_i_want(func_input_1, func_input_2);
Note that there is overhead associated with using anonymous functions like this, and this is not something I would do in code that would be called thousands of times.
In MATLAB 2010a, I found a neat way of doing what you are asking for.
It is simply to use the character "~" (without the quotes of course) as your dummy variable (as many as you want when returning multiple parameters). This also works for input parameters to functions if the functions are designed to handle missing data.
I don't know if this existed in previous versions, but I just came across it recently.
You can make a function (or anonymous function) that only returns selected outputs, e.g.
select = #(a,b) a(b);
Then you can call your function like this:
select(func,2);
select(func,1:3);
Or you can assign the output to a variable:
output(1,2:4) = select(func,1:3);
I don't see any reason not to use ans(n). Like this:
size(rand([5 10 20 40]));
b = ans(2);
It gives b = 10, and this way would be compatible with all MATLAB versions. Note that size() here is just used to represent any function that has multiple return variables.
Furthermore, this works to get the second output argument when you don't know how many arguments there will be! Whereas, if you do this:
[~, b] = size(a);
Then b = 8000! (You need to end with ~, to catch more arguments!)