Find the minimum positive difference between elements in vector - matlab

A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
I would like to create a vector C which returns the rownumber of the element in vector A with the smallest non-negative difference to each element in vector B.
So, given the example above, it should return:
C = [1 2 2 3 3 4 4 4]

I'm sure there are many ways to do this. Here's one:
A = [1 3 5 8]
B = [1 2 3 4 5 6 7 8]
%create matrices of the values to subtract
[a,b] = meshgrid(A,B);
%subtract
aLessB = a-b;
%make sure we don't use the negative values
aLessB(aLessB < 0) = Inf;
%sort the subtracted matrix
[dum, idx] = sort(aLessB, 2, 'ascend');
idx(:,1) is the solution you are looking for.

An alternative solution:
D = bsxfun(#minus, A', B);
D(D < 0) = Inf;
[~, C] = min(D, [], 1);

Related

Building matrices using column vector and matrix in matlab

I have a column vector A (6x1) with values [6 3 10 4 2 8]'; and a matrix B (6x5) with values
B = [1 2 3 0 4 ;
3 7 8 5 0 ;
0 9 1 0 1 ;
5 0 3 1 2 ;
4 6 7 6 4 ;
3 1 2 7 3]
I want to make five matrices with size 6x2 using Matlab.
The first column is vector A
The second column is columns from B, like [A, B(first col)], [A, B(second col)]
First matrix is [6 1; 3 3; 10 0; 4 5; 2 4; 8 3];
2nd matrix is [6 2; 3 7; 10 9; 4 0; 2 6; 8 1]
... and so on
Any help I really appreciate it
You could use a loop
C = NaN( size(B,1), 2, size(B,2) );
for ii = 1:size(B,2)
C(:,:,ii) = [A, B(:,ii)];
end
This gives you a 3D array, where each slice in the 3rd dimension is a 6x2 matrix (for this example) as desired. You would access the nth slice with C(:,:,n).
You can do this slightly more concisely with arrayfun, but it's basically a loop in disguise
C = arrayfun( #(ii) [A, B(:,ii)], 1:size(B,2), 'uni', 0 );
C = cat(3, C{:} );
You could omit the cat function if you're happy with results in a cell array, where you access the nth matrix with C{n}.
You could first make a copy of the columns of A, then concatenate A and B, and reshape:
At = repmat(A, 1, size(B,2));
C = reshape([At;B], 6, 2, []);
Or oneliner:
C = reshape([repmat(A, 1, size(B,2));B], 6, 2, []);
Then retrieve your matrices with C(:,:,k)
you can use this
first_matrix=[A,B(:,1)];
second_matrix=[A,B(:,2)];
third_matrix=[A,B(:,3)];
... and so on

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.

Design a simple matrix to group values from matrices

This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.

Find column locations of vector elements inside a matrix

Given a vector such as a = [2 5 9] and a matrix such as
8 11 5
b = 2 6 1
4 9 3
What's the best way to find which column of b contains each element of a? In this example I'd want an output like [1 3 2] because 2 is in the first column, 5 is in the third column, and 9 is in the second column. For my purposes it's safe to assume that a number can only appear in one column.
One approach -
[colID,~] = find(squeeze(any(bsxfun(#eq,b,permute(a,[1 3 2])),1)))
Or if you would like to avoid squeeze and any -
[~,colID,~] = ind2sub([size(b) numel(a)],find(bsxfun(#eq,b(:),a)))
Another way would be to use ismember:
A = [2 5 9];
B = [8 11 5; 2 6 1; 4 9 3];
[~, ind] = ismember(A,B);
[~, col] = ind2sub(size(B), ind)
col =
1 3 2
Another approach:
[~, index] = ismember(a, b);
[row, col] = ind2sub(size(b, 1), index);

how to get values of a matrix in MATLAB where the indices are given in a nx2 array

I have a matrix A of size nRows x nCols.
I have a nx2 matrix B which contains indices of the matrix A.
I want to get the values of A at the indices given in B.
lets say,
B = [1, 2;
2, 3;
3, 4]
A(1,2) = 1
A(2,3) = 2
A(3,4) = 1
I want to know any Matlab command which gives the following, given A and B (I don't want to use loops):
[1 2 1]
I guess this is what you are looking for:
A(sub2ind(size(A),B(:,1),B(:,2)))
This is what you want:
A = [1,2; 3, 4; 5, 6; 7,8; 9,0]; % this is your N by 2 matrix
B = [1,1; 1,2; 2,1; 3, 1; 4,2]; % these are your indexes
A(sub2ind(size(A), B(:,1), B(:,2)))
A =
1 2
3 4
5 6
7 8
9 0
B =
1 1
1 2
2 1
3 1
4 2
ans =
1
2
3
5
8