I have an array a of size ZxW.
Z = 20;
W = 30;
A = 40; %will be used below
size(a)
20 30
Then I apply to a two different transformations, and then after those I delete a and I cannot go back to it.
First transformation:
b = repelem(a(:,1),A,A);
Second transformation:
c = repmat(a,[1,1,A,A]);
d = c(:,1,:,:);
After those transformations and deleting a (which cannot be used for the following), I want to compare d and b using
assert( isequal(b,f) )
Where f is a transformation of d that makes the assertion true.
My first idea was a simple reshape:
f = reshape(squeeze(d),[Z*A,A]);
Which does not work as repelem and repmat move entries differently. How can I do this?
Thanks for the attention.
Sincerely
Luca
EDIT: changed
c = repmat(a,[A,A]);
with
c = repmat(a,[1,1,A,A]);
The answer (by Jan Simon) is:
f = reshape(permute(d, [3,1,4,2]), [Z*A,A]);
isequal(b, f) % 1: equal
Thanks for the help.
Luca
NOTE: This solution is obsoleted with the edited question, please refer to the other solutions posted.
Look closely at what the pattern of b and d are:
b = [1 1 1 2 2 2 3 3 3].'
d = [1 2 3 1 2 3 1 2 3].'
Hence, the transformation f can be:
f = reshape(d, [A, A]).'
f = f(:)
This will convert d to be exactly b or vice versa.
Related
I want to do multivariable assignment. I can do [a,b] = min([1 2 3]) but I can't do [a,b] = [1,2]. Why? Is there any workaround?
The [1,2] on the right hand side of the assignment is interpreted as array with the two elements 1 and 2.
If you want to do the multi-variable-assignment in one line, you can use deal in Matlab. This should work in Octave as well according to the documentation here.
>> [a,b] = deal(1,2)
a =
1
b =
2
The advantage of using deal is that it works in Matlab as well, where the solution with [a b] = {1 2}{:} won't.
Octave basics: How to assign variables from a vector
>> [a b c] = {5 6 7}{:}
a = 5
b = 6
c = 7
To adapt Cobusve's answer to Matlab, two lines are required:
>> h={5 6 7}
h =
[5] [6] [7]
>> [a b c]=h{:}
a =
5
b =
6
c =
7
I have a 7x21 matrix called A. Within this matrix there are three equally sized 7x7 submatrices. I call them B,C and D, where B = A(:,1:7), C = A(:,8:14) and D = A(:,15:21).
How can I produce a matrix E which is also 7x7 matrix where simply B, C and D are added up, i.e. E = B+C+D.
Thanks a lot for your help!
Generic code to get such an output -
N = 3; %// Number of submatrices
[m,n] = size(A) %// Get size [no. of cols must be multiple of N
E = reshape(sum(reshape(A,m*n/N,[]),2),m,n/N)
I don't see what's going to be more straightforward and concise than
E = A(:,1:7) + A(:,8:14) + A(:,15:21)
Unless you need an expression that generalizes in some way you're not describing...
Say I have two vectors: X=[x0,x1,x2]; Y=[y0,y1];
does there exist a single command in Matlab that I can generate a 2x3 matrix Z=f(X,Y),
where Z=[x0+y0, x1+y0, x2+y0; x0+y1, x1+y1, x2+y1]?
Thanks in advance.
It's a perfect case for bsxfun[C = bsxfun(fun,A,B) applies the element-by-element binary operation specified by the function handle fun to arrays A and B, with singleton expansion enabled. In this case, #plus is the function handle needed.] -
Z = bsxfun(#plus,X,Y.')
As an example, look at this -
X=[2,3,5]
Y=[1,4]
Z = bsxfun(#plus,X,Y.')
which gives the output -
X =
2 3 5
Y =
1 4
Z =
3 4 6
6 7 9
try this
Z = repmat(X,numel(Y),1) + repmat(Y',1,numel(X));
You can also use ndgrid:
[xx yy] = ndgrid(Y,X);
Z = xx+yy;
And there's the possibility to abuse kron as follows (but note that internally kron basically uses a variation of ndgrid):
Z = log(kron(exp(X),exp(Y).'));
Alternative to Nishant anwser would be using kron:
%for example
X=[1,2,3]; Y=[1,2]
Z = kron(X, ones(numel(Y), 1)) + kron(ones(1, numel(X)), Y');
Z =
2 3 4
3 4 5
If this would suit you, you could define a function:
% skron for sum kron
skron = #(X,Y) kron(X, ones(numel(Y), 1)) + kron(ones(1, numel(X)), Y');
Z = skron(X,Y);
In Matlab, sort returns both the sorted vector and an index vector showing which vector element has been moved where:
[v, ix] = sort(u);
Here, v is a vector containing all the elements of u, but sorted. ix is a vector showing the original position of each element of v in u. Using Matlab's syntax, u(ix) == v.
My question: How do I obtain u from v and ix?
Of course, I could simply use:
w = zero(size(v));
for i = 1:length(v)
w(ix(i)) = v(i)
end
if nnz(w == u) == length(u)
print('Success!');
else
print('Failed!');
end
But I am having this tip-of-the-tongue feeling that there is a more elegant, single-statement, vectorized way of doing this.
If you are wondering why one would need to do this instead of just using u: I was trying to implement the Benjamini-Hochberg procedure which adjusts each element of the vector based on its position after sorting, but recovering the original order after adjusting was important for me.
The solution is:
w(ix) = v;
This is a valid Matlab operation provided that w is either at least as big as v, or not yet declared.
Example:
>> u = [4 8 10 6 2];
>> [v, ix] = sort(u)
v = 2 4 6 8 10
ix = 5 1 4 2 3
>> u(ix)
ans = 2 4 6 8 10
>> w(ix) = v
w = 4 8 10 6 2
(Apologies for the trivial question-answer, but I realized the solution as I was typing the question, and thought it might be useful to someone.)
I want all neighbors of a point coordinate in a matrix at a distance d from it along with that point.
What is the most efficient way to generate such a sub-matrix ?
For example if A = [ 1 , 2 , 3 ; 4 , 5 , 6 ; 7 ,8 ,9]
then for d = 0 and data 5 i would get the answer as 5 but for d = 1 i will get the matrix A as the result since the size of A itself is 3X3.
At the same time if the index does not exist in the matrix then i should get 0 at that point.
so for data point 2 and d = 1 the answer would be [ 0 , 0 , 0 ; 1 , 2 ,3 ; 4 , 5 , 6]
How can i do it ?
Try this out ...
A = padarray( A , [d d] )
% assuming the data is at r row and c col do the following
A( r : r + 2d , c : c + 2 d )
I hope it works ... did'nt really check !!
Here's a solution. I'll leave you to turn it into a function. Let n denote the value at the centre of your sub-array, which is 5 in your example.
z = zeros(size(A,1)+2*d,size(A,2)+2*d);
z(d+1:d+size(A,1),d+1:d+size(A,2)) = A;
[r,c] = find(z==n);
z(r-d:r+d,c-d:c+d)
EDIT
Try this version, which is as inadequately tested as my earlier attempt. This still won't cope if the find expression returns multiple locations.
And I still make no warranties as to the efficiency of this.
To start with the case that you are inside A, instead of giving d=0 and data_point=5 you should give data_point=[2,2]. If you have it given as 5 you can convert by
ij = [ceil(data_point/size(A,1)), rem(data_point-1, size(A,1))+1]
or use find, as in High's answer, depending how to interpret your question.
The following function
function B = find_neigh(A,ij,d)
imin = max(ij(1)-d,1);
imax = min(ij(1)+d,size(A,1));
jmin = max(ij(2)-d,1);
jmax = min(ij(2)+d,size(A,2));
B = zeros(2*d+1,2*d+1);
r1 = max(2-ij(1)+d,1);
c1 = max(2-ij(2)+d,1);
B(r1:r1+imax-imin, c1:c1+jmax-jmin) = A(imin:imax,jmin:jmax);
should return you the desired result. Call it for example with
A = [1, 2, 3; 4, 5, 6; 7, 8, 9];
find_neigh(A,[1,2],1)
Edit: fixed two, no three bugs, and made it a function