The problem:
I want to index into the result of a function call that returns a variable number of output arguments without storing the result in a temporary.
getel = #(x,i) x(i); #% simple anonymous function to index into a vector
x = zeros(2,2,2);
row = getel(ind2sub(size(x), 8), 1) #% desired: 2 (row 2)
#% actual: 8 (linear index)-because ind2sub is returning 1 value only
[row col dep]=ind2sub(size(x),8) #% row=2, ind2sub returning 3 values
Example usage:
x(1).val1 = [1 2 3];
x(1).val2 = [2 1 2];
x(2).val1 = [2 1 2];
x(2).val2 = [1 0 0];
#% The normal way I would do this, with a temporary variable
[~,ind] = min(x(1).val2); #% ind=2
v(1) = x(1).val1(ind);
[~,ind] = min(x(2).val2); #% ind=2
v(2) = x(2).val1(ind);
#% I'd like to be able to do this with arrayfun:
v = arrayfun(#(s) s.val1(min(s.val2), x);
-------^ returns value of minimum, not index
The above arrayfun doesn't work - the form of min that is called returns one output: the minimum value. To make it work right, one option would be the following hypothetical function call:
v = arrayfun(#(s) s.val1(getoutputnum(2, 2, #min, s.val2)), x);
hypothetical function -----------^ ^ ^ ^-func ^--func args
which form (nargout) of func ---| |- which arg to return
I realize that for the above scenario, I could use
s.val1(find(s.val2==min(s.val2),1,'first'))
or other tricks, but that isn't possible in all cases.
In the case of ind2sub, I may want to know the index into a particular dimension (columns, say) - but the 1-output form of the function returns only a linear index value - the n-dimensional form needs to be called, even if the value of dimension 1 is what I care about.
Note: I realize that writing a function file would make this trivial: use ~ and the [out] = func(in) form. However, when writing scripts or just on the command line, it would be nice to be able to do this all within anonymous functions. I also realize that there are undoubtedly other ways to get around the problem; I would just like to know if it is possible to specify which form of a function to call, and perhaps which output number to be returned, without using the out=func(in) syntax, thus allowing functions to be nested much more nicely.
Could you do something like this?
In its own file:
function idx=mymin(x)
[~,idx] = min(x);
In your code:
v = arrayfun(#(s) s.val1(mymin(s.val2), x);
Might have syntax errors; I don't have MATLAB on the computer I'm writing this on. The idea is there though: just wrap MATLAB's min and capture the second argument, which is the logical indexing for the position of the minimum value in x.
I can get ind2sub() to return the variable number of args like this:
x = zeros(2,2,2);
c = cell(ndims(x),1);
[c{:}] = ind2sub(size(x), 8);
The c cell array will now have the 3D indices c = {2;2;2}.
[c{:}] = ind2sub(size(x), 2);
would produce c = {2;1;1}.
Is this what you were looking for?
Related
This is simplified but take as an example the following MATLAB function handle:
F = #(x)[x(1)-x(2);x(2)-x(3)]
The system has of course has many solutions. Is it possible to obtain a solution for a function like this one after substituting at least one variable? For example, substituting x(3)=1 the function would become:
G = #(x)[x(1)-x(2);x(2)-1]
And a solution for the other variables can be obtained. I use fsolve and it works quite well for the system of equations I have. Of course what I need to do can be done using the Symbolic Toolbox, but calling it in a big for loop makes it too slow to use for my code.
I'm trying to come up with some code that can return G given F and a set of indices in x to replace with given values.
What you're basically asking to do is have G call F with values in x reassigned based on a logical replacement index index and a set of replacement values values, which is doable but messy since anonymous functions can only have a single executable statement.
The solution is similar to what is done in this answer, but instead of using the functional form for subscripted reference we'll need to use the functional form for subscripted assignment: subsasgn. Here's what it would look like:
F = #(x)[x(1)-x(2); x(2)-x(3)];
values = [3 2 1];
index = logical([0 0 1]);
G = #(x) F(subsasgn(x, struct('type', '()', 'subs', {{index}}), values(index)));
And here's a test:
>> F([3 2 3])
ans =
1
-1
>> F([3 2 1]) % Replace the last element by 1
ans =
1
1
>> G([3 2 3]) % G handles replacing the last element by 1
ans =
1
1
I wish to include or (or any) within a function where the number of arguments (logical vectors) passed in can be more than two and can vary in number.
For example, the parent function may create
a=[1;0;0;0]
b=[0;1;0;0]
c=[0;0;0;1]
but the next time may add
d=[0;0;1;0]
how do I get it, in this case, to give me X=[1;1;0;1] the first time around and Y=[1;1;1;1] the second time? The number of vectors could be up to twenty so it would need to be able to recognise how many vectors are being passed in.
This is how I would do it:
function y = f(varargin)
y = any([varargin{:}], 2);
varargin is a cell array with the function input arguments. {:} generates a comma-separated list of those arguments, and [...] (or horzcat) concatenates them horizontally. So now we have a matrix with each vector in a column. Applying any along the second dimension gives the desired result.
Since the function contains a single statement you can also define it as an anonymous function:
f = #(varargin) any([varargin{:}], 2);
Example runs:
>> f([1; 1; 0; 0], [1; 0; 0; 1])
ans =
4×1 logical array
1
1
0
1
>> f([1; 1; 0; 0], [1; 0; 0; 1], [0; 0; 1; 0])
ans =
4×1 logical array
1
1
1
1
I'm sure you already thought of this:
a=[1;0;0;0]
b=[0;1;0;0]
c=[0;0;0;1]
a|b|c % returns [1;1;0;1]
However there is a much simpler answer to this:
any([a,b,c,d],2);
easily extendable by just concatinating the variables as above, before inputting it into the anyfunction. If you want to put it into a function here's way to do it:
function customOr(varargin)
any(cell2mat(varargin),2) % equivalent to any([varargin{:}],2);
end
customOr(a,b,c) % returns [1;1;0;1]
customOr(a,b,c,d) % returns [1;1;1;1]
I am trying out one of the matlab programming question.
Question:
Write a function called hulk that takes a row vector v as an input and
returns a matrix H whose first column consist of the elements of v,
whose second column consists of the squares of the elements of v, and
whose third column consists of the cubes of the elements v. For
example, if you call the function likes this, A = hulk(1:3) , then A
will be [ 1 1 1; 2 4 8; 3 9 27 ].
My Code:
function H = hulk(v)
H = [v; v.^2; v.^3];
size(H) = (n,3);
end
When I test my code using A = hulk(1:3), it throws an error on console.
Your function made an error for argument(s) 0
Am I doing something incorrect? Have I missed anything?
Remove the line size(H) = (n,3);
and add the line H = H';
Final code should be as follows
function H = hulk(v)
H = [v; v.^2; v.^3];
H = H';
end
Your code giving error in matlab editor on the size(H) = (n,3); line
That's why you should use the matlabeditor itself
For your future reference, you can very easily generalise this function in Matlab to allow the user to specify the number of cols in your output matrix. I also recommend that you make this function a bit more defensive by ensuring that you are working with column vectors even if your user submits a row vector.
function H = hulk(v, n)
%//Set default value for n to be 3 so it performs like your current function does when called with the same signature (i.e. only 1 argument)
if nargin < 2 %// nargin stands for "Number of ARGuments IN"
n = 3;
end if
%// Next force v to be a row vector using this trick (:)
%// Lastly use the very useful bsxfun function to perform the power calcs
H = bsxfun(#power, v(:), 1:n);
end
You could reduce the number of operations using cumprod. That way, each v.^k is computed as the previous v.^k times v:
function H = hulk(v, n)
H = cumprod(repmat(v,n,1),1);
The first input argument is the vector, and the second is the maximum exponent.
I've been searching the net for a couple of mornings and found nothing, hope you can help.
I have an anonymous function like this
f = #(x,y) [sin(2*pi*x).*cos(2*pi*y), cos(2*pi*x).*sin(2*pi*y)];
that needs to be evaluated on an array of points, something like
x = 0:0.1:1;
y = 0:0.1:1;
w = f(x',y');
Now, in the above example everything works fine, the result w is a 11x2 matrix with in each row the correct value f(x(i), y(i)).
The problem comes when I change my function to have constant values:
f = #(x,y) [0, 1];
Now, even with array inputs like before, I only get out a 1x2 array like w = [0,1];
while of course I want to have the same structure as before, i.e. a 11x2 matrix.
I have no idea why Matlab is doing this...
EDIT 1
Sorry, I thought it was pretty clear from what I wrote in the original question, but I see some of you asking, so here is a clarification: what I want is to have again a 11x2 matrix, since I am feeding the function with arrays with 11 elements.
This means I expect to have an output exactly like in the first example, just with changed values in it: a matrix with 11 rows and 2 columns, with only values 0 in the first column and only values 1 in the second, since for all x(i) and y(i) the answer should be the vector [0,1].
It means I expect to have:
w = [0 1
0 1
0 1
...
0 1]
seems pretty natural to me...
You are defining a function f = #(x,y) [0, 1]; which has the input parameters x,y and the output [0,1]. What else do you expect to happen?
Update:
This should match your description:
g=#(x,y)[zeros(size(x)),ones(size(y))]
g(x',y')
Defining an anonymous function f as
f = #(x,y) [0,1];
naturally returns [0,1] for any inputs x and y regardless of the length of those vectors.
This behavior puzzled me also until I realized that I expected f(a,b) to loop over a and b as if I had written
for inc = 1:length(a)
f(a(inc), b(inc))
end
However, f(a,b) does not loop over the length of its inputs, so it merely returns [0,1] regardless of the length of a and b.
The desired behavior can be obtained by defining f as
g=#(x,y)[zeros(size(x)),ones(size(y))]
as Daniel stated in his answer.
I'm trying to use MatLab code as a way to learn math as a programmer.
So reading I'm this post about subspaces and trying to build some simple matlab functions that do it for me.
Here is how far I got:
function performSubspaceTest(subset, numArgs)
% Just a quick and dirty function to perform subspace test on a vector(subset)
%
% INPUT
% subset is the anonymous function that defines the vector
% numArgs is the the number of argument that subset takes
% Author: Lasse Nørfeldt (Norfeldt)
% Date: 2012-05-30
% License: http://creativecommons.org/licenses/by-sa/3.0/
if numArgs == 1
subspaceTest = #(subset) single(rref(subset(rand)+subset(rand))) ...
== single(rref(rand*subset(rand)));
elseif numArgs == 2
subspaceTest = #(subset) single(rref(subset(rand,rand)+subset(rand,rand))) ...
== single(rref(rand*subset(rand,rand)));
end
% rand just gives a random number. Converting to single avoids round off
% errors.
% Know that the code can crash if numArgs isn't given or bigger than 2.
outcome = subspaceTest(subset);
if outcome == true
display(['subset IS a subspace of R^' num2str(size(outcome,2))])
else
display(['subset is NOT a subspace of R^' num2str(size(outcome,2))])
end
And these are the subset that I'm testing
%% Checking for subspaces
V = #(x) [x, 3*x]
performSubspaceTest(V, 1)
A = #(x) [x, 3*x+1]
performSubspaceTest(A, 1)
B = #(x) [x, x^2, x^3]
performSubspaceTest(B, 1)
C = #(x1, x3) [x1, 0, x3, -5*x1]
performSubspaceTest(C, 2)
running the code gives me this
V =
#(x)[x,3*x]
subset IS a subspace of R^2
A =
#(x)[x,3*x+1]
subset is NOT a subspace of R^2
B =
#(x)[x,x^2,x^3]
subset is NOT a subspace of R^3
C =
#(x1,x3)[x1,0,x3,-5*x1]
subset is NOT a subspace of R^4
The C is not working (only works if it only accepts one arg).
I know that my solution for numArgs is not optimal - but it was what I could come up with at the current moment..
Are there any way to optimize this code so C will work properly and perhaps avoid the elseif statments for more than 2 args..?
PS: I couldn't seem to find a build-in matlab function that does the hole thing for me..
Here's one approach. It tests if a given function represents a linear subspace or not. Technically it is only a probabilistic test, but the chance of it failing is vanishingly small.
First, we define a nice abstraction. This higher order function takes a function as its first argument, and applies the function to every row of the matrix x. This allows us to test many arguments to func at the same time.
function y = apply(func,x)
for k = 1:size(x,1)
y(k,:) = func(x(k,:));
end
Now we write the core function. Here func is a function of one argument (presumed to be a vector in R^m) which returns a vector in R^n. We apply func to 100 randomly selected vectors in R^m to get an output matrix. If func represents a linear subspace, then the rank of the output will be less than or equal to m.
function result = isSubspace(func,m)
inputs = rand(100,m);
outputs = apply(func,inputs);
result = rank(outputs) <= m;
Here it is in action. Note that the functions take only a single argument - where you wrote c(x1,x2)=[x1,0,x2] I write c(x) = [x(1),0,x(2)], which is slightly more verbose, but has the advantage that we don't have to mess around with if statements to decide how many arguments our function has - and this works for functions that take input in R^m for any m, not just 1 or 2.
>> v = #(x) [x,3*x]
>> isSubspace(v,1)
ans =
1
>> a = #(x) [x(1),3*x(1)+1]
>> isSubspace(a,1)
ans =
0
>> c = #(x) [x(1),0,x(2),-5*x(1)]
>> isSubspace(c,2)
ans =
1
The solution of not being optimal barely scratches the surface of the problem.
I think you're doing too much at once: rref should not be used and is complicating everything. especially for numArgs greater then 1.
Think it through: [1 0 3 -5] and [3 0 3 -5] are both members of C, but their sum [4 0 6 -10] (which belongs in C) is not linear product of the multiplication of one of the previous vectors (e.g. [2 0 6 -10] ). So all the rref in the world can't fix your problem.
So what can you do instead?
you need to check if
(randn*subset(randn,randn)+randn*subset(randn,randn)))
is a member of C, which, unless I'm mistaken is a difficult problem: Conceptually you need to iterate through every element of the vector and make sure it matches the predetermined condition. Alternatively, you can try to find a set such that C(x1,x2) gives you the right answer. In this case, you can use fminsearch to solve this problem numerically and verify the returned value is within a defined tolerance:
[s,error] = fminsearch(#(x) norm(C(x(1),x(2)) - [2 0 6 -10]),[1 1])
s =
1.999996976386119 6.000035034493023
error =
3.827680714104862e-05
Edit: you need to make sure you can use negative numbers in your multiplication, so don't use rand, but use something else. I changed it to randn.