Matlabs "splitapply" used on functions with multiple parameters - matlab

I don't understand matlabs splitapply function:
>> f=#(t,x) sum(sum(t),sum(x))
f =
function_handle with value:
#(t,x)sum(sum(t),sum(x))
>> splitapply(f,[1,0;0,0],[1,1;2,2],1:2)
ans =
1 0
I expected the two matrices to be split into columns and the two first columns fed to f, resulting in a total sum of 4=(1+0)+(1+2). Then both the second columns should be fed to f, resulting in the number 3=(0+0)+(1+2).
So I expected
ans =
4 3
But quite obviously that is not what happend. And I am not sure why. If I use splitapply on functions with only one argument, it seems to do what I expect:
>> splitapply(#sum,[1,1;2,3],1:2)
ans =
3 4
I would be glad if someone could point out what is happening. This is the documentation if someone else can understand it better than me: https://de.mathworks.com/help/matlab/ref/splitapply.html

You probably want
f = #(t,x) sum([sum(t) sum(x)])
or
f = #(t,x) sum(t)+sum(x)
rather than
f = #(t,x) sum(sum(t), sum(x))
The latter is interpreted as compute the sum of sum(t) along the dimension given by sum(x).
With this correction,
>> f = #(t,x) sum([sum(t) sum(x)]);
>> splitapply(f,[1,0;0,0],[1,1;2,2],1:2)
ans =
4 3

Related

How to assign values to variables in a handle function?

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

Matlab: can not simplify a symbolic scalar function use subs() in a simple case

It is just a simple case in matlab, something strange about function subs() happens and I don't know why.
I have read the official help doc and googled the error message but didn't find useful information.
Could someone tell me what wrong the the command "subs(f)"?
>> syms x w b f
>> f=x*w-b
f =
w*x - b
>> w=[1 2 3 ;4 5 6; 7 8 9 ]
w =
1 2 3
4 5 6
7 8 9
>> x=[1 2 3.44]'
x =
1.0000
2.0000
3.4400
>> b=[ 2 4 7 ]'
b =
2
4
7
>> f
f =
w*x - b
>> subs(f)
Error using symengine
New arrays must have the same dimensions or must be scalars.
Error in sym/subs>mupadsubs (line 140)
G = mupadmex('symobj::fullsubs',F.s,X2,Y2);
Error in sym/subs (line 125)
G = mupadsubs(F,X,Y);
here is a screenshot of the error message:
The Symbolic Toolbox operates from the standpoint that Symbolic Variables are scalars and any operation or expression in which they are present uses element-wise semantics. As states in the subs documentation:
If old is a scalar, and new is a vector or matrix, then subs(s,old,new) replaces all instances of old in s with new, performing all operations elementwise. All constant terms in s are replaced with the constant times a vector or matrix of all 1s.
So the expression undergoing substitution needs to play nice with element-wise application and expansion upon substitution. However, when the new arrays being substituted do no match size in every dimension (as is the case here with the coefficient matrix being rectangular versus the column vector), a dimension mismatch will more than likely occur in the engine. Even direct specification of the substitution with cell arrays throws the error:
>> wnum = [1 2 3 ;4 5 6; 7 8 9 ];
>> xnum = [1 2 3.44]';
>> bnum = [ 2 4 7 ]';
>> subs(f,{w,x,b},{wnum,xnum,bnum})
Error using symengine
New arrays must have the same dimensions or must be scalars.
Error in sym/subs>mupadsubs (line 140)
G = mupadmex('symobj::fullsubs',F.s,X2,Y2);
Error in sym/subs (line 125)
G = mupadsubs(F,X,Y);
While fully conforming dimensional substitutions will work just fine:
>> subs(f,{w,x,b},{xnum,xnum,xnum}); % All 3x1
>> subs(f,{w,x,b},{wnum,wnum,wnum}); % All 3x3
And all of this derives from the Symbolic Variables themselves being treated as scalars. The Symbolic work-around being to declare the variables as Symbolic Arrays to generate the individual elements of the arrays and allow for a one-to-one substitution:
>> w = sym('w',[3,3]);
>> x = sym('x',[3,1]);
>> b = sym('b',[3,1]);
>> f = w*x - b;
>> subs(f,[w,x,b],[wnum,xnum,bnum])
ans =
333/25
766/25
1174/25
Of course, the best course of action, if you can do so, is to avoid the Symbolic Toolbox entirely or as much as possible.
>> double(subs(f,[w,x,b],[wnum,xnum,bnum]))
ans =
13.3200
30.6400
46.9600
>> fnum = wnum*xnum - bnum
fnum =
13.3200
30.6400
46.9600
The above discussion is a very, very large reason as to why I leave Linear Algebra to the MATLAB run-time proper, aside from all of the performance increases associated with it. The Symbolic Toolbox, in my opinion, is best left to analysis of functions in one or more variables (I use it to create Taylor Series, Jacobians, and Hessians often enough) or high precision analysis of a small dimensional problem for investigative purposes.

Vector Function is Always Constant

New to MATLAB, and I need help with the following issue.
I want to create a function val=F(v,e) that takes in two inputs v, a 1xn vector, and a scalar e, and outputs a scalar val that counts the nonzero entries of the vector v-e, i.e. the vector v with e subtracted from all each of its entries. My code for the function is below:
function val = eff(vec, e)
val = sum( (vec - e > 0) );
end
When I evaluate the function at a single point it works as it should. but I want a plot of this function on (0,1). Plotting it gives a constant value over the entire range of e. I am using the following code on the main
figure
e = linspace(0,1);
plot(e, eff(rand(1,100),e),'o',e, e)
Also, when I use a small vector, say, rand(1,10), I get the following error message:
>Error using -
>
>Matrix dimensions must agree.
>
>Error in eff (line 3)
>
>val = sum( (vec - e > 0 ));
Is my function being too careless with matrix dimensions? Or is there an easier way to evaluate eff over a vector range?
Thanks in advance.
You have created a function which is designed to be applied only with a scalar e argument, and where passing e as an array would potentially cause errors ... but then you call it with e = linspace(0,1) which is an array.
The particular error when e is of size 10 is telling you that you cannot subtract it from a matrix of size 100.
When e happens to have the same size as vec, your function subtracts two equal-sized arrays, and returns their sum, which is a scalar. Therefore your plot is essentially doing something like plot(a_range, a_scalar), which is why it looks constant.
Instead, you should probably collect an array V for each value of e in a for loop, or using arrayfun, e.g.
e = linspace(0,1);
V = arrayfun(#eff, e);
and then plot e against V
Alternatively, you could rewrite your function such that it expects e to be an array, and your return value is an array of the same size as e, filled with the appropriate values.
without using arrayfun, your task can also be accomplished using broadcasting. I noticed you had this question tagged Octave as well as Matlab. Octave uses automatic broadcasting when you attempt elementwise operations with vectors in different dimensions. Matlab can do broadcasting with the bsxfun function. (if you want code that will run in either program, Octave also can use bsxfun.) Also, according to the release notes I believe Matlab 2016b will now include automatic broadcasting, although I cannot confirm yet that it will behave the same as Octave does.
Because your vectors vec and e are both row vectors, when you try to subtract them Matlab/Octave will subtract each element if they have the same size, or give a size mismatch error if they do not.
If you instead create one of the vectors as a column vector, broadcasting can take over. a simple example:
>> a = [1:4]
a =
1 2 3 4
>> b = [1:4]'
b =
1
2
3
4
>> a-b //Error in Matlab versions before 2016b
ans =
0 1 2 3
-1 0 1 2
-2 -1 0 1
-3 -2 -1 0
>> bsxfun(#minus,a,b) //works under Octave or Matlab
ans =
0 1 2 3
-1 0 1 2
-2 -1 0 1
-3 -2 -1 0
So, if you are running Octave, your code will run correctly if you just rewrite your function so the vectors use different dimensions. There are a number of ways to do this, but since both Matlab and Octave default to column ordering, you can use the : operator to force them to work the way you want. E.g.:
>> a = [1:4]
a =
1 2 3 4
>> a(:)
ans =
1
2
3
4
>> a(:)'
ans =
1 2 3 4
>> b = [1:4]'
b =
1
2
3
4
>> b(:)
ans =
1
2
3
4
>> b(:)'
ans =
1 2 3 4
So, after all that, you can rewrite your function:
function val = eff(vec, e)
vec = vec(:);
e = e(:)';
val = sum ( (vec-e ) > 0 );
end
If you're running matlab, or you want code that could run in both Octave and Matlab, you can just replace the last line of the function with:
sum ( bsxfun(#minus,vec,e) > 0 )
Finally, if you want, you can add some 'isvector' error checking at the beginning of the function in case you accidentally pass it an array. And note that had I chosen to make 'vec' a row vector and 'e' a column vector I would have had to tell the sum function which dimension to sum over. (it defaults to summing each column and returning a row vector, which matches the choices I made above.)
you function works fine as long as e is a scaler and not an array or matrix. You can then you looping or arrayfun (as already answered) to get a final answer
figure
e = rand(1,10); % create 10 random e numbers
vec = rand(1,100);
for inc = 1:length(e)
v(inc) = eff(vec,e(inc));
end
scatter(e,v);

Recurring Function with Matrix Input

I believe most functions in MATLAB should be able to receive matrix input and return the output in the form of matrix.
For example sqrt([1 4 9]) would return [1 2 3].
However, when I tried this recurring factorial function:
function k = fact(z)
if z ~= 0
k = z * fact(z-1);
else
k = 1;
end
end
It works perfectly when a number is input into fact. However, when a matrix is input into fact, it returns the matrix itself, without performing the factorial function.
E.g.
fact(3) returns 6
fact([1 2 3]) returns [1 2 3] instead of [1 2 6].
Any help is appreciated. Thank you very much!
Since MATLAB is not known to be good with recursive functions, how about a vectorized approach? Try this for a vector input -
mat1 = repmat([1:max(z)],[numel(z) 1])
mat1(bsxfun(#gt,1:max(z),z'))=1
output1 = prod(mat1,2)
Sample run -
z =
1 2 7
output1 =
1
2
5040
For the sake of answering your original question, here's the annoying loopy code for a vector or 2D matrix as input -
function k1 = fact1(z1)
k1 = zeros(size(z1));
for ii = 1:size(z1,1)
for jj = 1:size(z1,2)
z = z1(ii,jj);
if z ~= 0
k1(ii,jj) = z .* fact1(z-1);
else
k1(ii,jj) = 1;
end
end
end
return
Sample run -
>> fact1([1 2 7;3 2 1])
ans =
1 2 5040
6 2 1
You can use the gamma function to compute the factorial without recursion:
function k = fact(z)
k = gamma(z+1);
Example:
>> fact([1 2 3 4])
ans =
1 2 6 24
Not sure if all of you know, but there is an actual factorial function defined in MATLAB that can take in arrays / matrices of any size, and computes the factorial element-wise. For example:
k = factorial([1 2 3 4; 5 6 7 8])
k =
1 2 6 24
120 720 5040 40320
Even though this post is looking for a recursive implementation, and Divakar has provided a solution, I'd still like to put my two cents in and suggest an alternative. Also, let's say that we don't have access to factorial, and we want to compute this from first principles. What I would personally do is create a cell array that's the same size as the input matrix, but each element in this cell array would be a linear index array from 1 up to the number defined for each location in the original matrix. You would then apply prod to each cell element to compute the factorial. A precondition is that no number is less than 1, and that all elements are integers. As such:
z1 = ... ; %// Define input matrix here
z1_matr = arrayfun(#(x) 1:x, z1, 'uni', 0);
out = cellfun(#prod, z1_matr);
If z1 = [1 2 3 4; 5 6 7 8];, from my previous example, we get the same output with the above code:
out =
1 2 6 24
120 720 5040 40320
This will obviously be slower as there is an arrayfun then cellfun call immediately after, but I figured I'd add another method for the sake of just adding in another method :) Not sure how constructive this is, but I figured I'd add my own method and join Divakar and Luis Mendo :)

matlab constant anonymous function returns only one value instead of an array

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.