Any one knows where the error is? Many thanks!
beta=randn(50,1);
bsxfun(#(x1,x2) max([x1 x2 x1+x2]), beta, beta')
error message:
Error using horzcat
Dimensions of matrices being concatenated are not consistent.
Error in #(x1,x2)max([x1,x2,x1+x2])
I'm not 100% sure what you want to achieve, but the error is in the transposition of beta as third argument of bsxfun; it works like this:
beta=randn(50,1);
bsxfun(#(x1,x2) max([x1 x2 x1+x2]), beta, beta)
The second and third argument of bsxfun needs to be of the same size to apply element-wise binary operations to it.
Edit: From the manual (http://www.mathworks.de/de/help/matlab/ref/bsxfun.html):
fun can also be a handle to any binary element-wise function not
listed above. A binary element-wise function of the form C = fun(A,B)
accepts arrays A and B of arbitrary, but equal size and returns output
of the same size. Each element in the output array C is the result of
an operation on the corresponding elements of A and B only.
EDIT2: Is this, what you want?
A = rand(1,50);
[x, y] = ndgrid(1:length(A), 1:length(A));
idc = [x(:) y(:)];
allMin = min([A(idc(:,1)) A(idc(:,2)) A(idc(:,1))+A(idc(:,2))]);
First, with the second and third code-line I generate all possible combinations of indices (all pairs i/j), e.g.: If A has 3 entries, idc would look like:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
and then I'm building up a vector containing the value A(i), A(j) and A(i)+A(j) for each row of entries (i, j) and getting the min of it.
Here's what I got (using two max in bsxfun)
beta = randn(50,1);
res = bsxfun(#(x,y) max( x, max(y, x+y) ), beta, beta');
Verifying using repmat
tmp = max( cat(3, repmat(beta,[1 50]), repmat(beta',[50 1]), ...
repmat(beta,[1 50])+ repmat(beta',[50 1]) ), [], 3);
isequal( tmp, res )
Related
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);
I have a situation analogous to the following
z = magic(3) % Data matrix
y = [1 2 2]' % Column indices
So,
z =
8 1 6
3 5 7
4 9 2
y represents the column index I want for each row. It's saying I should take row 1 column 1, row 2 column 2, and row 3 column 2. The correct output is therefore 8 5 9.
I worked out I can get the correct output with the following
x = 1:3;
for i = 1:3
result(i) = z(x(i),y(i));
end
However, is it possible to do this without looping?
Two other possible ways I can suggest is to use sub2ind to find the linear indices that you can use to sample the matrix directly:
z = magic(3);
y = [1 2 2];
ind = sub2ind(size(z), 1:size(z,1), y);
result = z(ind);
We get:
>> result
result =
8 5 9
Another way is to use sparse to create a sparse matrix which you can turn into a logical matrix and then sample from the matrix with this logical matrix.
s = sparse(1:size(z,1), y, 1, size(z,1), size(z,2)) == 1; % Turn into logical
result = z(s);
We also get:
>> result
result =
8
5
9
Be advised that this only works provided that each row index linearly increases from 1 up to the end of the rows. This conveniently allows you to read the elements in the right order taking advantage of the column-major readout that MATLAB is based on. Also note that the output is also a column vector as opposed to a row vector.
The link posted by Adriaan is a great read for the next steps in accessing elements in a vectorized way: Linear indexing, logical indexing, and all that.
there are many ways to do this, one interesting way is to directly work out the indexes you want:
v = 0:size(y,2)-1; %generates a number from 0 to the size of your y vector -1
ind = y+v*size(z,2); %generates the indices you are looking for in each row
zinv = z';
zinv(ind)
>> ans =
8 5 9
For matrices with dimensions equal or less then 2 the command is:
For instance:
>> mat2str(ones(2,2))
ans =
[1 1;1 1]
However, as the help states, this does not work for higher dimensions:
>> mat2str(rand(2,2,2))
Error using mat2str (line 49)
Input matrix must be 2-D.
How to output matrices with higher dimensions than 2 with that is code compatible, without resorting to custom made for loops?
This isn't directly possible because there is no built-in character to represent concatenation in the third dimension (an analog to the comma and semicolon in 2D). One potential workaround for this would be to perform mat2str on all "slices" in the third dimension and wrap them in a call to cat which, when executed, would concatenate all of the 2D matrices in the third dimension to recreate your input matrix.
M = reshape(1:8, [2 2 2]);
arrays = arrayfun(#(k)mat2str(M(:,:,k)), 1:size(M, 3), 'uni', 0);
result = ['cat(3', sprintf(', %s', arrays{:}), ')'];
result =
'cat(3, [1 3;2 4], [5 7;6 8])'
isequal(eval(result), M)
1
UPDATE
After thinking about this some more, a more elegant solution is to flatten the input matrix, run mat2str on that, and then in the string used to recreate the data, we utilize reshape combined with the original dimensions to provide a command which will recreate the data. This will work for any dimension of data.
result = sprintf('reshape(%s, %s);', mat2str(M(:)), mat2str(size(M)));
So for the following 4D input
M = randi([0 9], 1, 2, 3, 4);
result = sprintf('reshape(%s, %s);', mat2str(M(:)), mat2str(size(M)));
'reshape([6;9;4;6;5;2;6;1;7;2;1;7;2;1;6;2;2;8;3;1;1;3;8;5], [1 2 3 4]);'
Now if we reconstruct the data using this generated string, we can ensure that we get the correct data back.
Mnew = eval(result);
size(Mnew)
1 2 3 4
isequal(Mnew, M)
1
By specifying both the class and precision inputs to mat2str, we can even better approximate the input data including floating point numbers.
M = rand(1,2,3,4,5);
result = sprintf('reshape(%s, %s);', mat2str(M(:),64,'class'), mat2str(size(M)));
isequal(eval(result), M)
1
What I intend to do is very simple but yet I haven't found a proper way to do it. I have a function handle which depends on two variables, for example:
f = #(i,j) i+j
(mine is quite more complicated, though)
What I'd like to do is to create a matrix M such that
M(i,j) = f(i,j)
Of course I could use a nested loop but I'm trying to avoid those. I've already managed to do this in Maple in a quite simple way:
f:=(i,j)->i+j;
M:=Matrix(N,f);
(Where N is the dimension of the matrix) But I need to use MATLAB for this. For now I'm sticking to the nested loops but I'd really appreciate your help!
Use bsxfun:
>> [ii jj] = ndgrid(1:4 ,1:5); %// change i and j limits as needed
>> M = bsxfun(f, ii, jj)
M =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
If your function f satisfies the following condition:
C = fun(A,B) accepts arrays A and B of arbitrary, but equal size and returns output of the same size. Each element in the output array C is the result of an operation on the corresponding elements of A and B only. fun must also support scalar expansion, such that if A or B is a scalar, C is the result of applying the scalar to every element in the other input array.
you can dispose of ndgrid. Just add a transpose (.') to the first (i) vector:
>> M = bsxfun(f, (1:4).', 1:5)
Function handles can accept matrices as inputs. Simply pass a square matrix of size N where the values corresponds to the row number for i, and a square matrix of size N where the values correspond to the column number for j.
N = 5;
f = #(i,j) i+j;
M = f(meshgrid(1:N+1), meshgrid(1:N+1)')
I have two vectors with the same elements but their order is not same. For eg
A
10
9
8
B
8
9
10
I want to find the mapping between the two
B2A
3
2
1
How can I do this in matlab efficiently?
I think the Matlab sort is efficient. So:
[~,I]=sort(A); %sort A; we want the indices, not the values
[~,J]=sort(B); %same with B
%I(1) and J(1) both point to the smallest value, and a similar statement is true
%for other pairs, even with repeated values.
%Now, find the index vector that sorts I
[~,K]=sort(I);
%if K(1) is k, then A(k) is the kth smallest entry in A, and the kth smallest
%entry in B is J(k)
%so B2A(1)=J(k)=J(K(1)), where BSA is the desired permutation vector
% A similar statement holds for the other entries
%so finally
B2A=J(K);
if the above were in script "findB2A" the following should be a check for it
N=1e4;
M=100;
A=floor(M*rand(1,N));
[~,I]=sort(rand(1,N));
B=A(I);
findB2A;
all(A==B(B2A))
There are a couple of ways of doing this. The most efficient in terms of lines of code is probably using ismember(). The return values are [Lia,Locb] = ismember(A,B), where Locb are the indices in B which correspond to the elements of A. You can do [~, B2A] = ismember(A, B) to get the result you want. If your version of MATLAB does not allow ~, supply a throwaway argument for the first output.
You must ensure that there is a 1-to-1 mapping to get meaningful results, otherwise the index will always point to the first matching element.
Here a solution :
arrayfun(#(x)find(x == B), A)
I tried with bigger arrays :
A = [ 7 5 2 9 1];
B = [ 1 9 7 5 2];
It gives the following result :
ans =
3 4 5 2 1
Edit
Because arrayfun is usually slower than the equivalent loop, here a solution with a loop:
T = length(A);
B2A = zeros(1, length(A));
for tt = 1:T
B2A(1, tt) = find(A(tt) == B);
end
I would go for Joe Serrano's answer using three chained sort's.
Another approach is to test all combinations for equality with bsxfun:
[~, B2A] = max(bsxfun(#eq, B(:), A(:).'));
This gives B2A such that B(B2A) equals A. If you want it the other way around (not clear from your example), simply reverse A and B within bsxfun.