Reputation: 5
I want to generate a square random matrix in MATLAB whose upper diagonal has equal number of elements less than 0.5 and greater than 0.5. I want to keep all the diagonal elements equal to zero and have below diagonal (lower triangle) same as above diagonal (upper triangle) elements. So the intended out put could be like below
0 a1 a2 a3
a1 0 a4 a5
a2 a4 0 a6
a3 a5 a6 0
where ai's are the random numbers distributed equally between (0,0.5) and (0.5,1).
Upvotes: 0
Views: 517
Reputation: 4644
You wrote that you want to "have below diagonal (lower triangle) [elements be the] same as above diagonal (upper triangle) elements." In the future you can just say that you want a matrix to be "symmetric," and that will be clear.
I wrote up some code which I think will work for your purposes:
function mat = generate_matrix( n )
% "n" is the number of rows / columns the output named "mat" will have.
sml_val_min = 0;
sml_val_max = 0.5;
big_val_min = 0.5;
big_val_max = 1;
% The number of elements in the upper triangular portion of the matrix can be
% represented by an Arithmetic Series.
% There is a row with one element, then a row with 2 elements, then a row
% with 3, on up to a row with n - 1 elements.
% So, there are 1 + 2 + ... + n-1 = (n-1)*n/2 elements in total.
numel_in_up_tri_portion = (n-1)*n/2;
% determine how many distinct small values we need to generate and how many large values
numel_sml = floor(numel_in_up_tri_portion/2);
numel_big = ceil(numel_in_up_tri_portion/2);
% Generate small values and large values
sml_vals = (sml_val_max - sml_val_min).*rand(1, numel_sml) + sml_val_min;
big_vals = (big_val_max - big_val_min).*rand(1, numel_big) + big_val_min;
% decide where in the matrix small values will go and where large values will go
sml_val_locations = randsample(numel_in_up_tri_portion, numel_sml);
big_val_locations = setdiff(1:numel_in_up_tri_portion, sml_val_locations);
%
[rs, cs] = convert_linear_index_to_row_and_col( sml_val_locations );
[rb, cb] = convert_linear_index_to_row_and_col( big_val_locations );
mat = zeros(n);
for k = 1:numel_sml
mat(rs(k), cs(k)) = sml_vals(k);
end
for k = 1:numel_big
mat(rb(k), cb(k)) = big_vals(k);
end
mat = mat + mat';
end % of function definition
function [row, col] = convert_linear_index_to_row_and_col( lin_ind )
unity = ones(size(lin_ind));
% Solve the quadratic equation (row^2 - row)/2 = lin_ind
row = ceil(0.5 * (unity + (unity + 8*lin_ind).^0.5));
%
col = lin_ind - 0.5*(row - unity).*(row - 2*unity);
end % of function definition
Upvotes: 0
Reputation: 19689
req=zeros(n); %initializing a matrix of size nxn
%finding the indexes of upper diagonal elements
Up_tri_ind = find(triu(true(size(req)), 1));
%finding the number of upper diagonal elements
temp=length(Up_tri_ind);
%Filling first half of the indexes with values less than 0.5
%and the other half with greater than 0.5
req(Up_tri_ind(1:temp/2))= 0.5*rand(1,temp/2);
req(Up_tri_ind(temp/2+1:end))= 0.5+0.5*rand(1,temp/2);
%Replacing the same elements in the lower diagonal
req=req+req.';
Note that this is only possible when number of elements in the upper diagonal or lower diagonal are even because half of an even number is also an integer whereas half of an odd number is never an integer.
And thus it is possible only if n
belongs to the following series:
4,5,8,9,12,13,16,17,....
Upvotes: 0
Reputation: 4558
It is possible to generate 2 equally large sets of random numbers (0,0.5) and (0.5,1) and scramble them into the matrix.
function test()
upperMatrix = triu(ones(4),1);
r0 = 0.5*rand(3,1); % smaller set
r1 = 0.5*rand(3,1)+0.5; % larger set
rfull = [r0;r1] % full set
permutation = randperm(6) % generate a scrambled vector of random number 1:6
upperMatrix(upperMatrix == 1) = rfull(permutation) % insert values to upper matrix
upperMatrix = upperMatrix + upperMatrix.' % make the matrix symmetric.
Note that I assume there is an even number of unique non-zero elements. This is what was stated in the problem formulation and in case you want something else you need to apply a special case. This can be for example to set last element to 0.5 or add an extra (0.5,1) number or extra (0,0.5) number or something else you can come up with and works for you.
Upvotes: 0