matlab - find indices of elements in x - matlab

I have a matrix x of size Nx2 (contains (x,y) coordinates) and a matrix c of size Px1 (P<=N) that contains certain x-coordinates which I'm interested in. For example:
x = [10 3; 21 9; 98 54; 4 30; 37 12];
c = [4 98];
I want to get the coordinates of the elements in c (in the above case [4 3]). How can I do this? I've only found a way when c is a 1x1 matrix (i.e. a scalar).

ismember can be used for testing membership of multiple values. You can slice the N-by-2 matrix to search only x-coordinates.
coords = [1 2; 3 4; 5 6; 7 8];
c = [3 7 99];
[v i] = ismember(c, coords(:, 1));
i =
[2 4 0]
i should contain the indices where values in c appear as the x-coordinate in coords, or a 0 if the element is not found.
If you have a recent version of Matlab, you can replace v with ~.

Related

Turning matrix diagonals to columns

I am looking for a matrix operation of the form: B = M*A*N where A is some general square matrix and M and N are the matrices I want to find.
Such that the columns of B are the diagonals of A. The first column the main diagonal, the second the diagonal shifted by 1 from the main and so on.
e.g. In MATLAB syntax:
A = [1, 2, 3
4, 5, 6
7, 8, 9]
and
B = [1, 2, 3
5, 6, 4
9, 7, 8]
Edit:
It seems a pure linear algebra solution doesn't exist. So I'll be more precise about what I was trying to do:
For some vector v of size 1 x m. Then define C = repmat(v,m,1). My matrix is A = C-C.';.
Therefore, A is essentially all differences of values in v but I'm only interested in the difference up to some distance between values.
Those are the diagonals of A; but m is so large that the construction of such m x m matrices causes out-of-memory issues.
I'm looking for a way to extract those diagonals in a way that is as efficient as possible (in MATLAB).
Thanks!
If you're not actually looking for a linear algebra solution, then I would argue that constructing three additional matrices the same size as A using two matrix multiplications is very inefficient in both time and space complexity. I'm not sure it's even possible to find a matrix solution, given my limited knowledge of linear algebra, but even if it is it's sure to be messy.
Since you say you only need the values along some diagonals, I'd construct only those diagonals using diag:
A = [1 2 3;
4 5 6;
7 8 9];
m = size(A, 1); % assume A is square
k = 1; % let's get the k'th diagonal
kdiag = [diag(A, k); diag(A, k-m)];
kdiag =
2
6
7
Diagonal 0 is the main diagonal, diagonal m-1 (for an mxm matrix) is the last. So if you wanted all of B you could easily loop:
B = zeros(size(A));
for k = 0:m-1
B(:,k+1) = [diag(A, k); diag(A, k-m)];
end
B =
1 2 3
5 6 4
9 7 8
From the comments:
For v some vector of size 1xm. Then B=repmat(v,m,1). My matrix is A=B-B.'; A is essentially all differences of values in v but I'm only interested in the difference up to some distance between values.
Let's say
m = 4;
v = [1 3 7 11];
If you construct the entire matrix,
B = repmat(v, m, 1);
A = B - B.';
A =
0 2 6 10
-2 0 4 8
-6 -4 0 4
-10 -8 -4 0
The main diagonal is zeros, so that's not very interesting. The next diagonal, which I'll call k = 1 is
[2 4 4 -10].'
You can construct this diagonal without constructing A or even B by shifting the elements of v:
k = 1;
diag1 = circshift(v, m-k, 2) - v;
diag1 =
2 4 4 -10
The main diagonal is given by k = 0, the last diagonal by k = m-1.
You can do this using the function toeplitz to create column indices for the reshuffling, then convert those to a linear index to use for reordering A, like so:
>> A = [1 2 3; 4 5 6; 7 8 9]
A =
1 2 3
4 5 6
7 8 9
>> n = size(A, 1);
>> index = repmat((1:n).', 1, n)+n*(toeplitz([1 n:-1:2], 1:n)-1);
>> B = zeros(n);
>> B(index) = A
B =
1 2 3
5 6 4
9 7 8
This will generalize to any size square matrix A.

MATLAB: Forming an array of matrices and do operations with respect to each matrix "element"

I have an array of matrix m such that
m1 = [1 2;3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
m = [m1 m2 m3]
m =
1 2 2 7 9 7
3 4 8 9 8 91
I also have a vector
v = [1 2 3];
such that i want the operations between v and m result in h such that
h = [1*m1 2*m2 3*m3] = [h1 h2 h3];
I imagine I have to do this in 3-dimensional array for h, which is a 3d array. Or maybe there are better ways.
Let A be a simple 2 by 2 matrix, rand(2,2).
From h i want to extract h1 h2 and h3 out(or better not doing any extraction) and perform operations to A such that
1.
h1*A*h1'
h2*A*h2'
h3*A*h3'
and
2.
h1*h1', h2*h2', h3*h3'.
Why i want to do this in array is because i have a lot of matrix mi so I want to avoid for loop by vectorization.
From what i could understand from the question, i suppose element-wise multiplication would be better choice. You would just have to use proper concatenation and repeatation of matrices.
m1 = [1 2; 3 4];
m2 = [2 7; 8 9];
m3 = [9 7; 8 91];
% Concatenate to create 3D matrix
m = cat(3,m1,m2,m3);
v = [1 2 3];
% Create similar 3D matrix
v1 = cat(3,ones(size(m1))*v(1),ones(size(m2))*v(2),ones(size(m3))*v(3));
% Simple element wise multiplication
h = m.*v1;
% Creating a repeated 3D matrix A, repetation is along third dimension
A = repmat(rand(2,2),[1 1 3]);
% Outputs
op_1 = h.*A.*permute(h,[2 1 3]);
op_2 = h.*permute(h,[2 1 3]);

How can i insert 2d random numbers into a given 2d matrix in matlab

I want to insert random numbers into a given 2D matrix in MATLAB. For example
if
A = [1 2 3;
4 5 6;
7 8 9];
and if B is a matrix which is uniformly distributed matrix, then I want a new matrix merging this two matrices (A & B), like
new matrix
C = [1 0.653 2 2.55 3;
4 4.3 5 5.4 6;
7 7.6 8 8.09 9]
How could I write MATLAB code for that?
If you've already got B and assuming that A is an n-by-m matrix and B is an n-by-m-1 matrix:
[n,m] = size(A);
C = zeros(n,2*m-1);
C(:,1:2:end) = A;
C(:,2:2:end) = B; % end-1 is not necessary since 2*m-1 is an odd number but if you prefer for readability then you can do C(:,2:2:end-1) = B
You could create B like this (depends on the limits of B which are not clear from your question)
B = A(:,1:end-1) + rand(n,m-1)*2 - 1

Rotate the rows of a matrix (like GAUSS function rotater)

I'm currently bringing some GAUSS code over to Matlab and I'm stuck trying to use the GAUSS "rotater" function.
The command reference entry for rotater says:
Purpose Rotates the rows of a matrix
Format y = rotater(x,r)
Input x: N x K matrix to be rotated. r: N x 1 or 1 x 1 matrix specifying the amount of rotation.
Output y: N x K rotated matrix.
Remarks The rotation is performed horizontally within each row of the matrix. A positive rotation value will cause the elements to move
to the right. A negative rotation will cause the elements to move to
the left. In either case, the elements that are pushed off the end of
the row will wrap around to the opposite end of the same row. If the rotation value is greater than or equal to the number of columns in x, then the rotation value will be calculated using (r % cols(x)).
Example 1
(I'm following Matlab's notation here, with straight brackets for matrices and a semicolon for a new ro)
If x = [1 2 3; 4 5 6], and r = [1; -1],then y = [3 1 2; 5 6 4]
Example 1
If x = [1 2 3; 4 5 6; 7 8 9; 10, 11, 12], and r = [0; 1; 2; 3], then y = [1 2 3; 6 4 5; 8 9 7; 10 11 12]
Maybe someone has found a function like that somewhere or can give me advice how to write it?
This can be done using bsxfun twice:
Compute rotated row indices by subtracting r with bsxfun and using mod. As usual, mod needs indices starting at 0, not 1. The rotated row indices are left as 0-based, because that's more convenient for step 2.
Get a linear index from columns and rotated rows, again using bsxfun. This linear index applied to x gives y:
Code:
[s1 s2] = size(x);
rows = mod(bsxfun(#plus, 1:s2, -r(:))-1, s2); % // step 1
y = x(bsxfun(#plus, rows*s1, (1:s1).')); %'// step 2
circshift is pretty close to what you're looking for except that 1) it works on columns rather than rows, and 2) it shifts the entire matrix by the same offset.
The first one is easy to fix, we just transpose. For the second one I haven't been able to find a vectorized approach, but in the meantime, here's a version with a for loop:
x = [1 2 3; 4 5 6; 7 8 9; 10 11 12]
r = [0 1 2 3]
B = x'
C = zeros(size(B));
for ii = 1:size(B,2)
C(:,ii) = circshift(B(:,ii),r(ii));
end
y = C'
The output is:
x =
1 2 3
4 5 6
7 8 9
10 11 12
r =
0 1 2 3
B =
1 4 7 10
2 5 8 11
3 6 9 12
y =
1 2 3
6 4 5
8 9 7
10 11 12
This can be done using a simple for loop to iterate over each row, and a function called 'circshift' from matlab.
I created a function the goes through each row and applies the appropriate shift to it. There may be more efficient ways to implement this, but this way works with your examples. I created a function
function rotated_arr = GaussRotate(input_array, rotation_vector)
[N,K] = size(input_array)
%creates array for return values
rotated_arr = zeros(N,K);
%if the rotation vector is a scalar
if (length(rotation_vector) == 1)
%replicate the value once for each row
rotation_vector = repmat(rotation_vector, [1,N]);
end
%if the rotation vector doesn't have as many entries as there are rows
%in the input array
if (length(rotation_vector) ~= N)
disp('ERROR GaussRotate: rotation_vector is the wrong size')
disp('if input_Array is NxK, rotation_vector must be Nx1 or 1x1')
return
end
%for each row
for idx=1:size(input_array,1)
%shift the row by the appropriate number of columns
%we use [0,shift] because we want to shift the columns, the row
%stays where it is (even though this is a 1xN at this point we
%still specify rows vs columns)
rotated_arr(idx,:) = circshift(input_array(idx,:),[0,rotation_vector(idx)]);
end
end
then simply called it with your examples
x = [1 2 3; 4 5 6];
r = [1; -1];
y = GaussRotate(x,r)
%produces [3 1 2; 5 6 4]
%I also made it support the 1x1 case
r = [-1]
%this will shift all elements one column to the left
y = GaussRotate(x,r)
%produces [2 3 1; 5 6 4]
x = [1 2 3; 4 5 6; 7 8 9; 10, 11, 12]
r = [0; 1; 2; 3]
y = GaussRotate(x,r)
%produces [1 2 3; 6 4 5; 8 9 7; 10 11 12]

Construct a matrix from existing two other matrices, all with different sizes

I have two matrices
a = randi ([0 10], 5, 6)
b = randi ([0 10], 2, 45)
Now I want to construct a matrix c of size 8 x 15 with all the elements of a and b. Is it possible to do it in a single line code? Some suggestions please.
Here is an example of what I'm trying to do:
a = [1 4 6;
5 8 0;
3 7 9;
4 10 5];
b = [5 6;
5 0];
c = [1 4 6 5;
8 0 3 7;
9 4 10 5;
5 6 5 0]
The specifications for how to combine a and b aren't clear. Here is one way to do it.
Create a single column vector built from a and b. Then reshape that column vector into a matrix.
c = reshape( [ a(:); b(:) ], 8, 15);
This will only work if the numel(a) + numel(b) equals the total number of elements in c.
Attempts to execute c = reshape( [ a(:); b(:) ], 7,12); will fail as you aren't providing enough elements to create an 7x12 matrix.
Update
Noufal's comment on this answer changes the problem reqs a bit. Basically you stil create the column vector but you only populate C depending on how many elements you have at your disposal:
A = rand(5,6);
B = rand(2,45);
C = zeros(8,10);
tmp = [A(:); B(:)]; % create temporary column vector
maxIdx = min( [numel(tmp), numel(C)] ); % determine if tmp or C has fewer elements
C(1:maxIdx) = tmp(1:maxIdx); % fill C from tmp using indices 1:maxIdx