Reputation: 175
I want to create a matrix where the middle diagonal is symmetrically decreasing to the sides, like this:
5 4 3 2 1
4 5 4 3 2
3 4 5 4 3
2 3 4 5 4
1 2 3 4 5
The matrix has to be 100x100 and the values are between 0
and 1
.
Until now I only get the edges and the middle diagonal, but can't get the idea on how to automatically fill the rest.
v = ones(1,100);
green = diag(v);
green(:,1) = fliplr(0:1/99:1);
green(1,:) = fliplr(0:1/99:1);
green(100,:) = 0:1/99:1;
green(:,100) = 0:1/99:1;
Upvotes: 6
Views: 443
Reputation: 104474
I'm surprised no one has recommended the toeplitz
matrix to you:
n = 5;
out = toeplitz(n:-1:1);
We get:
out =
5 4 3 2 1
4 5 4 3 2
3 4 5 4 3
2 3 4 5 4
1 2 3 4 5
If you want to normalize this to [0,1]
, simply do standard normalization such that:
out_new = (out - 1) / (n - 1)
... and so:
>> out = (out - 1) / (n - 1)
out =
1.0000 0.7500 0.5000 0.2500 0
0.7500 1.0000 0.7500 0.5000 0.2500
0.5000 0.7500 1.0000 0.7500 0.5000
0.2500 0.5000 0.7500 1.0000 0.7500
0 0.2500 0.5000 0.7500 1.0000
Upvotes: 6
Reputation: 221524
How about some code-golfing
-
n = 5
M = mod(bsxfun(@plus,n:-1:1,(0:n-1)'),n)
out = triu(M)+tril(n-M)
For your actual case, since you need to have values in the range [0,1]
, you can scale out
, like so -
out = (out - 1)/max(out(:)-1)
Sample run -
>> n = 5;
M = mod(bsxfun(@plus,n:-1:1,(0:n-1)'),n);
out = triu(M)+tril(n-M);
>> out
out =
5 4 3 2 1
4 5 4 3 2
3 4 5 4 3
2 3 4 5 4
1 2 3 4 5
>> out = (out - 1)/max(out(:)-1)
out =
1 0.75 0.5 0.25 0
0.75 1 0.75 0.5 0.25
0.5 0.75 1 0.75 0.5
0.25 0.5 0.75 1 0.75
0 0.25 0.5 0.75 1
Upvotes: 5
Reputation: 769
To look for a vectorized solution consider using spdiags()
.
n = 5;
A = repmat([1:n-1,n:-1:1],n,1);
B = full(spdiags(A,-n+1:n-1,n,n));
This will return:
5 4 3 2 1
4 5 4 3 2
3 4 5 4 3
2 3 4 5 4
1 2 3 4 5
As @Adriaan pointed out B = B/n
will transform the matrix values between 0 and 1.
Upvotes: 7
Reputation: 18177
N = 100; %// size of your matrix
v = ones(1,N); %// get a vector of ones
D = N*diag(v); %// set the main diagonal
for ii = 1:size(D,1)-1
tmp = (N-ii)*diag(v(1:end-ii),ii); %//positive direction off-
tmp2 = (N-ii)*diag(v(1:end-ii),-ii); %//negative direction off-diagonal
D = D+tmp+tmp2; %// Add them up
end
D = D/N; %// scale values to between 0 and 1
The trick here is to use the indexing variable, ii
, as a counter to simultaneously decrease the multiplication, N-ii
, decrease the length of v
, v(1:end-ii)
and increase the offset of the diagonal within diag
, ii
or -ii
.
Just to verify plot the results using imagesc(D)
:
Upvotes: 4