Alter number sort / number sequence - matlab

I have an array / number sequence a=[1,2,3,4,5] and I'm trying
to create an array / number sequence that looks like a_new below:
The columns represent the orders / index the numbers should go in.
a_new=...
[1,2,3,4,5;
2,1,2,3,4;
3,3,1,2,3;
4,4,4,1,2;
5,5,5,5,1]
My thoughts where to use circshift but quickly found out that would not work.
a=[1,2,3,4,5];
for n=1:5
a_wrong(:,n)=circshift(a(:)',[0 n])(:)
end
produces
a_wrong=[
5 4 3 2 1
1 5 4 3 2
2 1 5 4 3
3 2 1 5 4
4 3 2 1 5]
Any thoughts? It doesn't need to use circshift if that won't work.
PS: I'm using Octave 4.2 which is similar to Matlab

There are probably quite a few different ways to generate this matrix. Here's one using the functions repmat, toeplitz, tril, and triu:
>> a_new = tril(repmat(a.', 1, numel(a)), -1)+triu(toeplitz(a))
a_new =
1 2 3 4 5
2 1 2 3 4
3 3 1 2 3
4 4 4 1 2
5 5 5 5 1

I'm not sure about a built-in function, but this should work;
a=[1,2,3,4,5];
a_out = ones(length(a), length(a))
for n=1:5
a_out(n,:) = [n*ones(n-1),a(n:end)]
end
I do not have Octave or MATLAB installed on my computer, so I cannot test it. This may have a silly error, forgive me for that!

You can use spdiags to generate the matrix:
n = numel(a);
a_new = spdiags([repmat(flip(a).',1,n); repmat(a,n-1,1)],(1-n):0);

Related

Reshape a matrix by splitting it after k columns in MATLAB

Suppose that I have a matrix , let's call it A, as follows:
1 2 3 4 5 1 2 3 4 5
0 2 4 6 8 1 3 5 7 9
And I want to reshape it into a matrix like this:
1 2 3 4 5
0 2 4 6 8
1 2 3 4 5
1 3 5 7 9
So, basically, what I want to be done is that MATLAB first reads a block of size (2,5) and then splits the remaining matrix to the next row and then repeats this so on so forth until we get something like in my example.
I tried to do this using MATLAB's reshape command in several ways but I failed. Any help is appreciated. In case that it matters, my original data is larger. It's (2,1080). Thanks.
I don't believe you can do this in a single command, but perhaps someone will correct me. If speed isn't a huge concern a for loop should work fine.
Alternatively you can get your results by reshaping each row of A and then placing the results into every other row of a new matrix. This will also work with your larger data.
A = [1 2 3 4 5 1 2 3 4 5
0 2 4 6 8 1 3 5 7 9];
An = zeros(numel(A)/5, 5); % Set up new, empty matrix
An(1:2:end,:) = reshape(A(1,:), 5, [])'; % Write the first row of A to every other row of An
An(2:2:end,:) = reshape(A(2,:), 5, [])' % Write second row of A to remaining rows
An =
1 2 3 4 5
0 2 4 6 8
1 2 3 4 5
1 3 5 7 9
You may need to read more about indexing in the Matlab's documentation.
For your example, it is easy to do the following
A=[1 2 3 4 5 1 2 3 4 5; 0 2 4 6 8 1 3 5 7 9]
a1=A(:,1:5); % extract all rows, and columns from 1 to 5
a2=A(:,6:end); % extract all rows, and columns from 6 to end
B=[a1;a2] % construct a new matrix.
It is not difficult to build some sort of loops to extract the rest.
Here's a way you can do it in one line using the reshape and permute commands:
B = reshape(permute(reshape(A,2,5,[]), [1,3,2]), [], 5);
The reshape(A,2,5,[]) command reshapes your A matrix into a three-dimensional tensor of dimension 2 x 5 x nblocks, where nblocks is the number of blocks in A in the horizontal direction. The permute command then swaps the 2nd and 3rd dimensions of this 3D tensor, so that it becomes a 2 x nblocks x 5 tensor. The final reshape command then transforms the 3D tensor into a matrix of dimension (2*nblocks) x 5.
Looking at the results at each stage may give you a better idea of what's happening.

How to change the value of the diagonal column of the matrix?

How do I change the list of value to all 1? I need the top right to bottom left also end up with 1.
rc = input('Please enter a value for rc: ');
mat = ones(rc,rc);
for i = 1:rc
for j = 1:rc
mat(i,j) = (i-1)+(j-1);
end
end
final = mat
final(diag(final)) = 1 % this won't work?
Code for the original problem -
final(1:size(final,1)+1:end)=1
Explanation: As an example consider a 5x5 final matrix, the diagonal elements would have indices as (1,1), (2,2) .. (5,5). Convert these to linear indices - 1, 7 and so on till the very last element, which is exactly what 1:size(final,1)+1:end gets us.
Edit : If you would like to set the diagonal(from top right to bottom left elements) as 1, one approach would be -
final(fliplr(eye(size(final)))==1)=1
Explanation: In this case as well we can use linear indexing, but just for more readability and maybe a little fun, we can use logical indexing with a proper mask, which is being created with fliplr(eye(size(final)))==1.
But, if you care about performance, you can use linear indexing here as well, like this -
final(sub2ind(size(final),1:size(final,1),size(final,2):-1:1))=1
Explanation: Here we are creating the linear indices with the rows and columns indices of the elements to be set. The rows here would be - 1:size(final,1) and columns are size(final,2):-1:1. We feed these two to sub2ind to get us the linear indices that we can use to index into final and set them to 1.
If you would to squeeze out the max performance here, go with this raw version of sub2ind -
final([size(final,2)-1:-1:0]*size(final,1) + [1:size(final,1)])=1
All of the approaches specified so far are great methods for doing what you're asking.
However, I'd like to provide another viewpoint and something that I've noticed in your code, as well as an interesting property of this matrix that may or may not have been noticed. All of the anti-diagonal values in your matrix have values equal to rc - 1.
As such, if you want to set all of the anti-diagonal values to 1, you can cheat and simply find those values equal to rc-1 and set these to 1. In other words:
final(final == rc-1) = 1;
Minor note on efficiency
As a means of efficiency, you can do the same thing your two for loops are doing when constructing mat by using the hankel command:
mat = hankel(0:rc-1,rc-1:2*(rc-1))
How hankel works in this case is that the first row of the matrix is specified by the vector of 0:rc-1. After, each row that follows incrementally shifts values to the left and adds an increasing value of 1 to the right. This keeps going until you encounter the vector seen in the second argument, and at this point we stop. In other words, if we did:
mat = hankel(0:3,3:6)
This is what we get:
mat =
0 1 2 3
1 2 3 4
2 3 4 5
3 4 5 6
Therefore, by specifying rc = 5, this is the matrix I get with hankel, which is identical to what your code produces (before setting the anti-diagonal to 1):
mat =
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
Tying it all together
With hankel and the cheat that I mentioned, we can compute what you are asking in three lines of code - with the first line of code asking for the dimensions of the matrix:
rc = input('Please enter a value for rc: ');
mat = hankel(0:rc-1, rc-1:2*(rc-1));
mat(mat == rc-1) = 1;
mat contains your final matrix. Therefore, with rc = 5, this is the matrix I get:
mat =
0 1 2 3 1
1 2 3 1 5
2 3 1 5 6
3 1 5 6 7
1 5 6 7 8
Here's a simple method where I just add/subtract the appropriate matrices to end up with the right thing:
final=mat-diag(diag(mat-1))+fliplr(diag([2-rc zeros(1,rc-2) 2-rc]))
Here is one way to do it:
Say we have a the square matrix:
a = ones(5, 5)*5
a =
5 5 5 5 5
5 5 5 5 5
5 5 5 5 5
5 5 5 5 5
5 5 5 5 5
You can remove the diagonal, then create a diagonal list of ones to replace it:
a = a - fliplr(diag(diag(fliplr(a)))) + fliplr(diag(ones(length(a), 1)))
a =
5 5 5 5 1
5 5 5 1 5
5 5 1 5 5
5 1 5 5 5
1 5 5 5 5
The diag(ones(length(a), 1)) can be any vector, ie. 1->5:
a = a - fliplr(diag(diag(fliplr(a)))) + fliplr(diag(1:length(a)))
a =
5 5 5 5 1
5 5 5 2 5
5 5 3 5 5
5 4 5 5 5
5 5 5 5 5

left cyclic permutation

I want to make left cyclic permutation using MATLAB.
Consider matrix p :
p = [2 3 4 5];
Output :
[2 3 4 5;
3 4 5 2;
4 5 2 3;
5 2 3 4];
I hope the code is available for bigger data. Anyone please help me to make this in code using MATLAB.
A loop free alternative:
[X, Y] = meshgrid(1:numel(p));
p(mod(X+Y-2,numel(p))+1)
This is one approach:
cell2mat(arrayfun(#(n) circshift(p,[0 -n]),0:3,'uni',0).')
ans =
2 3 4 5
3 4 5 2
4 5 2 3
5 2 3 4
Note that arrayfun is really just a loop disguised as a one-liner. Thus explicitly writing out a loop to do the same thing might be equally fast/slow.

MATLAB Concatenate vectors with unequal dimensions

Lets say I have got vector1:
2
3
5
6
7
9
And a vector2:
1
2
3
Now I would like to obtain the following matrix:
2 1
3 2
5 3
6 1
7 2
9 3
That is, I want to add vector2 as a column next to vector1 until the new column is completely filled. I have to do this with a lot of vectors with different sizes. The only thing I know in advance is that the length of vector1 is an integer multiple of the length of vector2.
Any suggestions?
Use repmat to replicate the smaller matrix.
a = [2 3 5 6 7 9]';
b = [1 2 3]';
c = [a repmat(b, length(a) / length(b), 1)]
Result:
c =
2 1
3 2
5 3
6 1
7 2
9 3
You can then replicate the vector:
[vector1, repmat(vector2,n,1)]
where n is your multiple of vector2.
This could be an alternative
[x [y'; y']]

Efficient way to make a multi-diagonal matrix

Is there an efficient way to produce square multi-diagonal matricies such as these:
[[1,2,3],
[2,1,2],
[3,2,1]]
[[1,2,3,4,5],
[2,1,2,3,4],
[3,2,1,2,3],
[4,3,2,1,2],
[5,4,3,2,1]]
My efforts so far have produced the following:
t=10
sum=zeros(t,t)
for i=1:t
sum+=diag(ones(1,i)*(t-i)+1,t-i);
end
sum
sum+sum'-diag(ones(1,10),0)
The command toeplitz does exactly what you want:
toeplitz([1,2,3,4,5,6])
ans =
1 2 3 4 5 6
2 1 2 3 4 5
3 2 1 2 3 4
4 3 2 1 2 3
5 4 3 2 1 2
6 5 4 3 2 1
What you are looking for is called a symmetric (Hermitian) toeplitz matrix.
I'm not familiar with matlab, but I found this documentation on mathworks: