How to split an array as argument values in matlab? - matlab

In my matlab script, I have a function handler
F=#(x1,x2)6+2*x1^1+3*x2^2;
This gives me an anonymous function as F that takes 2 arguments and returns the value. I also have an array of values
x = [1 2];
With the above, how can I do
F(x)
In other words, something like F(1, 2) but I want to use x, I don't want to hard code values, and it also needs to work for any dimension size, I don't want to hard code it for 2-dimension like in the above example. Basically what I'm looking for is a way to turn an array into arguments.
Can this be done in matlab?
Thanks

To turn an array into its arguments: first turn the array into a cell array (with num2cell), and then turn the cell array into a comma-separated list (with {:}):
xcell = num2cell(x);
F(xcell{:})

Does this work?
F=#(x)6+2*x(1)^1+3*x(2)^2;
xx = [1 2];
F(xx)
ans =
20

Related

Passing A Variable Number of Arguments into a Function

In Matlab, I have a variable length cell of values:
C={A1,...,An}
How should I pass and distribute these values into a function able to receive a variable number of arguments?
f(A1,...,An)
Ultimately if not possible, how should I modify the beginning of this function for making this work?
You need to convert the cell array into a comma-separated list via curly-brace indexing, that is, use C{:}.
Example with the reshape function:
>> C = {ones(3,4), 2, 2, 3};
>> y = reshape(C{:});
>> size(y) % check
ans =
2 2 3
This is exactly what 'varargin' does for you. Read in multiple variables, e.g. f(a,b,c), and store them in a cell-array.
Then you could go for one of these 'quick and dirty' processing methods:
function asdf(varargin)
yourarguments=[varargin{:}]; % if all numerical
yourargumentscontain=contains(varargin,'asdf'); %if strings contained
all_processed_args=cellfun(#(x) whateveryouwant_function(x), varargin); %for older versions of matlab
end
For more here's documentation: https://ch.mathworks.com/help/matlab/matlab_prog/parse-function-inputs.html

MATLAB: return both arguments from ISMEMBER when used inside SPLITAPPLY

How can I access both arguments of ismember when it is used inside splitapply?
slitapply only returns scalar values for each group, so in order to compute nonscalar values for each group (as returned by the first argument of ismemebr), one has to enclose the anonymous function (in this case ismember) inside curly brackets {} to return a cell array.
But now, when I provide two output arguments to splitapply, I get an error:
Output argument "varargout{2}" (and maybe others) not assigned during call to
"#(x,y) {ismember(x,y)}"
ADD 1
I can create another function, say, ismember2cell which would apply ismember and turn outputs into cell arrays:
function [a, b] = ismember2cell(x,y)
[a,b] = ismember(x,y);
a = {a};
b = {b};
end
but maybe there is a solution which doesn't require this workaround.
One potentially faster option is to just do what splitapply is already doing under the hood by splitting your data into cell arrays (using functions like mat2cell or accumarray) and then using cellfun to apply your function across them. Using cellfun will allow you to easily capture multiple outputs (such as from ismember). For example:
% Sample data:
A = [1 2 3 4 5];
B = [1 2 1 5 5];
G = [1 1 1 2 2]; % Group index
% Group data into cell arrays:
cellA = accumarray(G(:), A(:), [], #(x) {x(:).'}); % See note below about (:).' syntax
cellB = accumarray(G(:), B(:), [], #(x) {x(:).'});
% Apply function:
[Lia, Locb] = cellfun(#ismember, cellA, cellB, 'UniformOutput', false);
NOTE: My sample data are row vectors, but I had to use the colon operator to reshape them into column vectors when passing them to accumarray (it wants columns). Once distributed into a cell array, each piece of the vector would still be a column vector, and I simply wanted to keep them as row vectors to match the original sample data. The syntax (:).' is a colon reshaping followed by a nonconjugate transpose, ensuring a row vector as a result no matter the shape of x. In this case I probably could have just used .', but I've gotten into the habit of never assuming what the shape of a variable is.
I cannot find a global solution, but the accepted answer of this post helps me to define a helper function for your problem:
function varargout = out2cell(varargin)
[x{1:nargout}]=feval(varargin{:});
varargout = num2cell(x);
I think that you may succeed in calling
splitapply(#(x,y) out2cell(#ismember, x, y), A, B);

Printing progress in command window

I'd like to use fprintf to show code execution progress in the command window.
I've got a N x 1 array of structures, let's call it myStructure. Each element has the fields name and data. I'd like to print the name side by side with the number of data points, like such:
name1 number1
name2 number2
name3 number3
name4 number4
...
I can use repmat N times along with fprintf. The problem with that is that all the numbers have to come in between the names in a cell array C.
fprintf(repmat('%s\t%d',N,1),C{:})
I can use cellfun to get the names and number of datapoints.
names = {myStucture.name};
numpoints = cellfun(#numel,{myStructure.data});
However I'm not sure how to get this into a cell array with alternating elements for C to make the fprintf work.
Is there a way to do this? Is there a better way to get fprintf to behave as I desire?
You're very close. What I would do is change your cellfun call so that the output is a cell array instead of a numeric array. Use the 'UniformOutput' flag and set this to 0 or false.
When you're done, make a new cell array where both the name cell array and the size cell array are stacked on top of each other. You can then call fprintf once.
% Save the names in a cell array
A = {myStructure.name};
% Save the sizes in another cell array
B = cellfun(#numel, {myStructure.data}, 'UniformOutput', 0);
% Create a master cell array where the first row are the names
% and the second row are the sizes
out = [A; B];
% Print out the elements side-by-side
fprintf('%s\t%d\n', out{:});
The trick with the third line of code is that when you unroll the cell array using {:}, this creates a comma-separated list unrolled in column-major format, and so doing out{:} actually gives you:
A{1}, B{1}, A{2}, B{2}, ..., A{n}, B{n}
... which provides the interleaving you need. Therefore, providing this order into fprintf coincides with the format specifiers that are specified and thus gives you what you need. That's why it's important to stack the cell arrays so that each column gives the information you need.
Minor Note
Of course one should never forget that one of the easiest ways to tackle your problem is to just use a simple for loop. Even though for loops are considered bad practice, their performance has come a long way throughout MATLAB's evolution.
Simply put, just do this:
for ii = 1 : numel(myStructure)
fprintf('%s\t%d\n', myStructure(ii).name, numel(myStructure(ii).data));
end
The above code is arguably more readable in comparison to what we did above with cell arrays. You're accessing the structure directly rather than having to create intermediate variables for the purpose of calling fprintf once.
Example Run
Here's an example of this running. Using the data shown below:
clear myStructure;
myStructure(1).name = 'hello';
myStructure(1).data = rand(5,1);
myStructure(2).name = 'hi';
myStructure(2).data = zeros(3,3);
myStructure(3).name = 'huh';
myStructure(3).data = ones(6,4);
I get the following output after running the printing code:
hello 5
hi 9
huh 24
We can see that the sizes are correct as the first element in the structure is simply a random 5 element vector, the second element is a 3 x 3 = 9 zeroes matrix while the last element is a 6 x 4 = 24 ones matrix.

How to get multiple outputs of a function in a vector?

Say I have a function whose outputs are two reals a and b
[a,b]=function(c)
I'd like to get all the outputs in a vector v.
v=function(c) doesn't do what I want, v is 'a' only.
Of course here I could do v=[a,b].
But the function in question is ind2sub for a N-D array so it gives n outputs that I'd like to have in a vector directly.
Is there a way to do it?
Thanks very much!
You can use a cell array and a comma-separated list like so:
X = cell(N, 1);
[X{:}] = function(C);
The syntax X{:} is in fact expanded to [X{1}, X{2}, ...], which provides a valid sink for your function. As a result, each output variable will be stored in a different cell in X.
If each output variable is a scalar, you can flatten out the cell array into a vector by using yet another comma-separated list expansion:
v = [X{:}];

Retrieving element index in spfun, cellfun, arrayfun, etc. in MATLAB

Is there any way to retrieve the index of the element on which a function called by cellfun, arrayfun or spfun acts? (i.e. retrieve the index of the element within the scope of the function).
For the sake of simplicity, imagine I have the following toy example:
S = spdiags([1:4]',0,4,4)
f = spfun(#(x) 2*x,S)
which builds a 4x4 sparse diagonal matrix and then multiplies each element by 2.
And say that now, instead of multiplying each element by the constant number 2, I would like to multiply it by the index the element has in the original matrix, i.e. assuming that linear_index holds the index for each element, it would be something like this:
S = spdiags([1:4]',0,4,4)
f = spfun(#(x) linear_index*x,S)
However, note the code above does not work (linear_index is undeclared).
This question is partially motivated by the fact that blocproc gives you access to block_struct.location, which one could argue references the location (~index) of the current element within the full object (an image in this case):
block_struct.location: A two-element vector, [row col], that specifies
the position of the first pixel (minimum-row, minimum-column) of the
block data in the input image.
No, but you can supply the linear index as extra argument.
Both cellfun and arrayfun accept multiple input arrays. Thus, with e.g. arrayfun, you can write
a = [1 1 2 2];
lin_idx = 1:4;
out = arrayfun(#(x,y)x*y,a,lin_idx);
This doesn't work with spfun, unfortunately, since it only accepts a single input (the sparse array).
You can possibly use arrayfun instead, like so:
S = spdiags([1:4]',0,4,4);
lin_idx = find(S);
out = spones(S);
out(lin_idx) = arrayfun(#(x,y)x*y,full(S(lin_idx)),lin_idx);
%# or
out(lin_idx) = S(lin_idx) .* lin_idx;
Note that the call to full won't get you into memory trouble, since S(lin_idx) is 0% sparse.
You can create a sparse matrix with linear_index filling instead of values.
Create A:
A(find(S))=find(S)
Then use A and S without spfun, e.g.: A.*S. This runs very fast.
It's simple. Just make a cell like:
C = num2cell(1:length(S));
then:
out=arrayfun(#(x,c) c*x,S,C)