How to produce random symmetric matrix given the number of vertices? - matlab

Is there a simple way to produce a random matrix of 0's and 1's, that is symmetric across the diagonal (with only zeros in the diagonal), given the number of vertices?
Example:
somefunction(3) = [ 0 1 1;
1 0 0;
1 0 0];
somefunction(4) = [ 0 1 1 1;
1 0 0 1;
1 0 0 1;
1 1 1 0];

You can generate a random matrix and extract lower triangular part of it then do OR with its transpose:
n = 4;
a=tril(randi(0:1,n),-1);
result = a|a.';

Related

Create a neighbourhood graph from a given binary matrix using matlab

I am trying to create a neighbourhood graph from a given binary matrix B. Neighbourhood graph (A) is defined as an adjacency matrix such that
(A(i,j) = A(j,i) = 1)
if the original matrix B(i) = B(j) = 1 and i and j are adjacent to each (left, right, up, down or diagonal). Here I used the linear subscript to access the original matrix B. For example, consider the below matrix
B = [ 0 1 0;
0 1 1;
0 0 0 ];
My A will be a 9 * 9 graph as given below
A = [ 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0;
0 0 0 0 1 0 0 1 0;
0 0 0 1 0 0 0 1 0;
0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 0 0;
0 0 0 1 1 0 0 0 0;
0 0 0 0 0 0 0 0 0 ];
Since in the original B matrix, B(4), B(5) and B(8) are adjacent with corresponding entries 1, the adjacency matrix A has 1 at A(4,5), A(5,4), A(4,8), A(8,4), A(5,8) and A(8,5).
How can I create such an adjacency matrix A given the matrix B in an efficient way?
This doesn't require any toolbox, and works for square or rectangular matrices. It uses array operations with complex numbers.
Consider a binary matrix B of size M×N.
Create an M×N matrix, t, that contains the complex coordinates of each nonzero entry of B. That is, entry t(r,c) contains r+1j*c if B(r,c) is nonzero, and NaN otherwise.
Compute an M*N×M*N matrix, d, containing the absolute difference for each pair of entries of B. Pairs of entries of B that are nonzero and adjacent will produce 1 or sqrt(2) in matrix d.
Build the result matrix, A, such that it contains 1 iff the corresponding entry in d equals 1 or sqrt(2). Equivalently, and more robust to numerical errors, iff the corresponding entry in d is between 0 and 1.5.
Code:
B = [0 1 0; 0 1 1; 0 0 0]; % input
t = bsxfun(#times, B, (1:size(B,1)).') + bsxfun(#times, B, 1j*(1:size(B,2)));
t(t==0) = NaN; % step 1
d = abs(bsxfun(#minus, t(:), t(:).')); % step 2
A = d>0 & d<1.5; % step 3
To get B back from A:
B2 = zeros(sqrt(size(A,1)));
B2(any(A,1)) = 1;
Here is a solution using image processing toolbox* that creates sparse matrix representation of the adjacency matrix:
B = [ 0 1 0;
0 1 1;
0 0 0 ]
n = numel(B);
C = zeros(size(B));
f = find(B);
C(f) = f;
D = padarray(C,[1 1]);
%If you don't have image processing toolbox
%D = zeros(size(C)+2);
%D(2:end-1,2:end-1)=C;
E = bsxfun(#times, im2col(D,[3 3]) , reshape(B, 1,[]));
[~ ,y] = find(E);
result = sparse(nonzeros(E),y,1,n,n);
result(1:n+1:end) = 0;
*More efficient implementation of im2col can be found here.

How to permute elements of a vector by another vector to obtain a matrix of permutations

I want to obtain all the possible permutations of one vector elements by another vector elements. For example one vector is A=[0 0 0 0] and another is B=[1 1]. I want to replace the elements of A by B to obtain all the permutations in a matrix like this [1 1 0 0; 1 0 1 0; 1 0 0 1; 0 1 1 0; 0 1 0 1; 0 0 1 1]. The length of real A is big and I should be able to choose the length of B_max and to obtain all the permutations of A with B=[1], [1 1], [1 1 1],..., B_max.
Thanks a lot
Actually, since A and B are always defined, respectively, as a vector of zeros and a vector of ones, this computation is much easier than you may think. The only constraints you should respect concerns B, which shoud not be empty and it's elements cannot be greater than or equal to the number of elements in A... because after that threshold A will become a vector of ones and calculating its permutations will be just a waste of CPU cycles.
Here is the core function of the script, which undertakes the creation of the unique permutations of 0 and 1 given the target vector X:
function p = uperms(X)
n = numel(X);
k = sum(X);
c = nchoosek(1:n,k);
m = size(c,1);
p = zeros(m,n);
p(repmat((1-m:0)',1,k) + m*c) = 1;
end
And here is the full code:
clear();
clc();
% Define the main parameter: the number of elements in A...
A_len = 4;
% Compute the elements of B accordingly...
B_len = A_len - 1;
B_seq = 1:B_len;
% Compute the possible mixtures of A and B...
X = tril(ones(A_len));
X = X(B_seq,:);
% Compute the unique permutations...
p = [];
for i = B_seq
p = [p; uperms(X(i,:).')];
end
Output for A_len = 4:
p =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1

MATLAB: Generate all possible N x N matrices with specific constraints

Suppose you have an initial N-by-N matrix, with all diagonal elements equal to zero. You want to generate all possible N-by-N matrices such that:
all diagonal elements continue to be zero
columns and rows keep the sum from the initial matrix
all elements are positive integers (including zero)
For example, for this 3-by-3 initial matrix:
0 1 3
2 0 1
3 2 0
one possible variation is:
0 0 4
3 0 0
2 3 0
An initial idea for an answer, which can certainly be further improved.
You can start thinking of a way to make matrices that have zeros on the diagonal and where rows and columns sum to zeros. If these can be constructed easily, then you can obtain your result by adding your initial matrix with all of them.
e.g.:
[ 0 1 -2 1;
1 0 -1 0;
-1 2 0 -1;
0 -3 3 0];
You can even restrict these 'helper' matrices to have maximally a single 1 and a single -1 on each row/column. All others can be constructed from them.
e.g.
A = [ 0 -1 2 -1;
2 0 -2 0;
-2 1 0 1;
0 0 0 0];
B = [ 0 -1 1 0;
1 0 -1 0;
-1 1 0 0;
0 0 0 0];
C = [ 0 0 1 -1;
1 0 -1 0;
-1 0 0 1;
0 0 0 0];
% A equals B+C
I think this at least reduces your problem a bit. Good luck!

Finding X binary numbers with n non-zero digits for large X. - Matlab

Is there a more efficient method for generating X binary numbers (that have n non-zero digits) for a range of 1 to N? I have developed the following solution:
Totalcombos = nchoosek(N,n);
floor = floor(log2(Totalcombos));
L = 2.^floor;
NumElem = 2^N-1;
i=0;
x=1;
%Creates Index combination LUT
while 1
%Produces Binary from 1 : NumElem
binNum= de2bi(x,N,'right-msb')';
x=x+1;
%Finds number of bits in each binary number
NumOfBits = sum(binNum);
%Creates a matrix of binary numbers from 1:NumElem with n 1's
if NumOfBits == n
i=i+1;
ISmatrixShapes{i} = binNum(:,:);
end
if i==L
break
end
end
ISmatrixShape2=cell2mat(ISmatrixShapes);
ISmatrixShape=ISmatrixShape2(:,1:L)';
Is there a way to generate these values without a massive number of loop iterations?
This generates all N-digit binary numbers that have n ones and N-n zeros:
N = 5;
n = 3;
ind = nchoosek(1:N, n);
S = size(ind,1);
result = zeros(S,N);
result(bsxfun(#plus, (ind-1)*S, (1:S).')) = 1;
It works by generating all combinations of n positions of ones out of the N possible positions (nchoosek line), and then filling those values with 1 using linear indexing (bsxfun line).
The result in this example is
result =
1 1 1 0 0
1 1 0 1 0
1 1 0 0 1
1 0 1 1 0
1 0 1 0 1
1 0 0 1 1
0 1 1 1 0
0 1 1 0 1
0 1 0 1 1
0 0 1 1 1
Another, less efficient approach is to generate all permutations of a vector containing n ones and N-n zeros, and then removing duplicates:
result = unique(perms([ones(1,n) zeros(1,N-n)]), 'rows');

How to create symmetric zero and one matrix

I need to create a 100*100 symmetric matrix that has random distribution of zeros and ones, but the diagonal should be all zeros, how can I do that?
This is one way to do it:
N = 100; % size of square matrix
p = 0.5; % probability of 0s
A = triu(rand(N)>p, 1); % matrix of 0s and 1s (upper triangular part)
A = A + A'; % now it is symmetric
You can use a uniform distribution to generate your random numbers:
n = 100;
a = round(rand(n,n));
Now set the diagonal entries to zero (as discussed here by Jonas):
a(logical(eye(size(a)))) = 0;
Symmetric component:
aSym = floor((a + a')/2);
Example for n = 5:
aSym =
0 0 0 0 0
0 0 1 0 1
0 1 0 0 1
0 0 0 0 0
0 1 1 0 0
Edit: At randomatlabuser's suggestion, added line to calc the symmetric component of the matrix and eliminated loop to zero out entries on the diagonal