Create index vector efficiently in matlab - matlab

Given three positive integers x,y, and z, such that x>y. What is the most efficient way to create the following vector:
1,2,3,..,x-y,x+1,x+2,x+3,..,2x-y,2x+1,2x+2,2x+3,..,3x-y,3x+1,...,..,zx+1,zx+2,zx+3,..,zx-y

This problem can be seen as a matrix, in which you add (1:x-y) to the various rows, and (0:z)*x) to the various columns. This can be done efficiently using bsxfun. To obtain the final result, you have to flatten the matrix to a column vector with (:) and transpose it to get the desired row vector:
>> x = 10; y = 7; z = 3;
>> vector = bsxfun(#plus, (1:(x-y)).', (0:z)*x);
>> vector = vector(:).'
vector =
1 2 3 11 12 13 21 22 23 31 32 33

Using matrix multiplication (column vector x row vector), an alternative solution is:
x = 10; y = 7; z = 3;
a = (1:x-y).'*ones(1,x-y) + ones(x-y,1)*(0:x:x*(z-1));
a = a(:).';

Related

Get the first four minimum values in a matrix

I have a matrix:
X =
0 81 13 15 100 2
11 0 6 10 200 8
19 22 0 20 300 23
I want to get the first four minimal values in the whole array X with the indices of each value in the array. For example I should get vector v = [2 6 8 10] and the index of each value in X.
Also, I want to ignore the zero values when the row number equals the column number.
I have tried to use the min and sort functions, but I am not sure how to do it.
I would suggest the following
X2 = X;
X2(~~eye(size(X2))) = inf; %// or X2(logical(eye(size(X2)))) = inf
[val, idx] = sort(X2(:));
result = val(1:4);
[idxRow, idxCol] = ind2sub(size(X), idx(1:4));
Use:
vals = sort(X(~eye(size(X)))); %takes non diagonal values and sort the result
res = vals(1:4) %finds the first 4 elements (which are the smallest)
[row, col] = find(ismember(X,res)); %gets the indices
result:
res = [2; 6; 8; 10]
By The way, if you don't want to ignore all the diagonal values, only the zero ones, use:
vals = sort(X(~eye(size(X)) | (eye(size(X)) & X~=0)));
Sort all but the ones on the diagonal and then find the indices of the ones which are smaller than or equal to the 4th element of sorted array and not on the diagonal:
T=sort(X(~eye(size(X))));
v = T(1:4);
[I,J] = find(X <= v(end) & ~eye(size(X)));
Just want to add to drorco's perfect answer how to find indexes of this first elements:
indexes = arrayfun( #(a) find(X==a), res);
or if you want to get numbers of rows and columns:
[r,c] = arrayfun( #(a) find(X==a), res);
P.S. it works perfectly if all elements except zeros in X are unique.

How do I create this matrix on Matlab?

I am trying to create a matrix (32 x 32) with -1 on its main diagonal and 1 in its first and second superdiagonals. 0 everywhere else.
A = eye(32)* -1;
That gives me a matrix with -1 on its main diagonal, how do I proceed?
n=32;
toeplitz([-1; zeros(n-1,1)],[-1 1 1 zeros(1,n-3)])
is what you need. This will create a non-symmetric Toeplitz matrix (a band matrix), the first column of which is given by [-1; zeros(32-1,1)], the first row by [-1 1 1 zeros(1,32-3)]. You could also define a function with size n as input parameter, if necessary.
You can use spdiags to set the diagonals directly into a sparse matrix and full-it if desired.
n = 32;
Asparse = spdiags(ones(n,1)*[-1,1,1],[0,1,2],n,n);
Afull = full(Asparse);
n = 32
A = -1*eye(n); %Create 32x32 Identity
A(n+1:n+1:n^2) = 1; %Set 1st Superdiagonal to 1
A(2*n+1:n+1:n^2) = 1; %Set 2nd Superdiagonal to 1
Note that MATLAB uses column-major order for matrices. For the 1st superdiagonal, we start with the (n+1)th element and choose every (n+1)th element thereon. We do a similar operation for 2nd superdiagonal except we start from (2*n+1)th element.
Just using diag and eye:
n = 32;
z = ones(n-1,1);
A = diag(z,1)+diag(z(1:n-2),2)-eye(n);
There's also:
n = 32;
A = gallery('triw',n,1,2)-2*eye(n)
using the gallery function with the 'triw' option.
diag allows you to create a matrix passing a diagonal:
-diag(ones(n,1),0)+diag(ones(n-1,1),1)+diag(ones(n-2,1),2)
Last parameter 0 for the main diagonal, 1 and 2 for the super diagonals.
If I can suggest more esoteric code, first create a vector full of 1s, then create the identity matrix, then shift create a diagonal matrix with these 1s with the vector and shift it to the right by 1, decreasing the amount of elements in the vector, then do it again for the last superdiagonal.
n = 32;
vec = ones(n,1);
out = -eye(n) + diag(vec(1:end-1),1) + diag(vec(1:end-2),2);
N = 32;
A = -diag(ones(N,1)); % diagonal
tmp1=diag(ones(N-1,1),1); %1st supra
tmp1=diag(ones(N-2,1),2); #2nd supra
A = A+tmp1+tmp2;
using diag
Yet another approach: this uses convmtx from the Signal Processing Toolbox:
n = 32; %// matrix size
v = [-1 1 1]; %// vector with values
M = convmtx(v, n);
M = M(:,1:end-numel(v)+1);

Changing the size of a matrix in MATLAB

I am given the following matrices A of size 3x1 and B of size 5x1
A = B=
1 A
2 B
3 C
D
E
I want to convert matrix C in a 15x2 matrix
C =
1 A
1 B
1 C
1 D
1 E
2 A
.
.
.
3 E
How can I make it?
Can be done with repmat
D = repmat(A',size(B,1),1);
C = [D(:),repmat(B,size(A,1),1)]
Here's a different alternative based on code for generating truth tables from Generate All Possible combinations of a Matrix in Matlab
ind = dec2base(0:power(5,2)-1,5)-47;
C = [A(ind(1:15,1) + 48, B(ind(1:15,2)];
And if you want to generalize it
m = max(size(A,1),size(B,1));
n = size(A,1)*size(B,1);
col = 2;
ind = dec2base(0:power(n,col)-1,n)-47;
ind = ind(1:n,:);
C = [A(ind(:,1) + 48, B(ind(:,2)];
The + 48 is just to convert your A matrix from a numerical matrix to a char matrix so that C can hold both number and letters. You can leave it out if A was already a char matrix.
What's useful about this technique is that by changing col, this generalizes to combing more than just 2 vectors in a similar fashion

How to multiply each row of a matrix by corresponding column of another matrix in matlab?

I have two matrices A and B. A is N-by-L matrix and B is L-by-N matrix.
A = [1 2 3;
4 5 6];
B = [ 7 8;
9 10;
11 12];
I would like to multiply the each row of the first matrix by the corresponding column of the second matrix. After the multiplication I would have a (Nx1) vector. The result would be
C = [ 1*7 + 2*9 + 3*11,
4*8 + 5*10 + 6*12];
I can perform the multiplication with a for loop, but it is not efficient for large matrices.
ASize = size(A);
for i = 1:ASize(1),
C(i) = A(i,:) * B(:,i);
end
Is there a better way to do this?
I think this should do the trick:
C = sum(A.*B', 2);
I think this will work better and is simple
C=diag(A*B);

Obtain matrix of indices in octave / matlab

Given some multidimensional matrix A in Octave / Matlab,
What's the easiest way to get a matrix of the same size as A where all elements are replaced by their index along the k'th dimension
ie for the matrix
A =
ans(:,:,1) =
0.095287 0.191905
0.226278 0.749100
ans(:,:,2) =
0.076826 0.131639
0.862747 0.699016
I want a function f such that
f(A,1) =
ans(:,:,1) =
1 1
2 2
ans(:,:,2) =
1 1
2 2
f(A,2) =
ans(:,:,1) =
1 2
1 2
ans(:,:,2) =
1 2
1 2
and
f(A, 3) =
ans(:,:,1) =
1 1
1 1
ans(:,:,2) =
2 2
2 2
Also, given a sparse matrix B
What's the easiest way to get another sparse matrix of the same size where the nonzero elements are replaced by their index along the k'th dimension? (so same problem as above, but for only the nonzero elements)
Ideally I'm looking for a way which is well-vectorized for octave (meaning it doesn't explicitly loop over anything)
CLARIFICATION: For the sparse matrix one, I'm looking for a solution which does not involve creating a full size(B) matrix at any point
ndgrid() does what you want, although not in the format you are looking for. If you know the dims of the input A beforehand, you can use the following line to create the N-dimentional mesh grid:
% for matrix a where ndims(a) == 3
[x, y, z] = ndgrid (1:size(a,1), 1:size(a,2), 1:size(a,3));
% x is like f(a, 1)
% y is like f(a, 2)
% z is like f(a, 3)
You may be able to write a custom wrapper around ndgrid() to convert it to the function format you are looking for.
In case anyone's curious, since I didn't know about ndgrid, here's the answer I came up with:
function [y] = indices(a,k)
s = size(a);
n = s(k);
D = length(s);
x = permute(a,[k,1:(k-1),(k+1):D]);
y = reshape(x,n,[]);
y = diag(1:n) * ones(size(y));
y = reshape(y,size(x));
y = permute(y,[(2:k),1,(k+1):D]);
endfunction
function [y] = spindices(a,k)
s = size(a);
n = s(k);
D = length(s);
x = permute(a,[k,1:(k-1),(k+1):D]);
y = reshape(x,n,[]);
y = spdiag(1:n) * spones(y);
y = reshape(y,size(x));
y = permute(y,[(2:k),1,(k+1):D]);
endfunction