Reputation: 242
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.
Upvotes: 2
Views: 132
Reputation: 22215
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.
Upvotes: 2
Reputation: 1610
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.)
Upvotes: 1
Reputation: 1
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);
Upvotes: 0