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.
Related
I have a matrix D = zeros (30, 432); i want to assign d = [ 1 1 0 0; 0 0 1 1; 0 0 0 0];
to the diagonals of matrix D. i have the code below but it doesn't allow me to assign d for every diagonal values in D.
[N,~,P,Q]=size(D);
diagIndex=repmat(logical(eye(N)),[1 1 P Q]);
D(diagIndex)=d;
The output for 30x432 matrix would be like :
d 0 0 0
0 d 0 0
0 0 d 0
0 0 0 d
You can use spdiags to create a diagonal [10 x 108] sparse matrix then use kron to scale and fill the matrix.
d = [ 1 1 0 0; 0 0 1 1; 0 0 0 0]
size_D=[30, 432];
sz = size_D./size(d);
diagonal = spdiags(ones(sz(1),1),0,sz(1),sz(2));
result = kron(diagonal ,d);
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
In each iteration I want to add 1 randomly to binary vector,
Let say
iteration = 1,
k = [0 0 0 0 0 0 0 0 0 0]
iteration = 2,
k = [0 0 0 0 1 0 0 0 0 0]
iteration = 3,
k = [0 0 1 0 0 0 0 1 0 0]
, that goes up to length(find(k)) = 5;
Am thinking of for loop but I don't have an idea how to start.
If it's important to have the intermediate vectors (those with 1, 2, ... 4 ones) as well as the final one, you can generate a random permutation and, in your example, use the first 5 indices one at a time:
n = 9; %// number of elements in vector
m = 5; %// max number of 1's in vector
k = zeros(1, n);
disp(k); %// output vector of all 0's
idx = randperm(n);
for p = 1:m
k(idx(p)) = 1;
disp(k);
end
Here's a sample run:
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 1
1 0 0 1 0 0 0 0 1
1 0 0 1 1 0 0 0 1
1 1 0 1 1 0 0 0 1
I wouldn't even use a loop. I would generate a random permutation of indices that sample from a vector going from 1 up to the length of k without replacement then just set these locations to 1. randperm suits the task well:
N = 10; %// Length 10 vector
num_vals = 5; %// 5 values to populate
ind = randperm(N, num_vals); %// Generate a vector from 1 to N and sample num_vals values from this vector
k = zeros(1, N); %// Initialize output vector k to zero
k(ind) = 1; %// Set the right values to 1
Here are some sample runs when I run this code a few times:
k =
0 0 1 1 0 1 1 0 0 1
k =
1 0 0 0 1 0 1 1 0 1
k =
1 0 0 0 1 0 1 1 0 1
k =
0 1 1 1 0 0 1 0 0 1
However, if you insist on using a loop, you can generate a vector from 1 up to the desired length, randomly choose an index in this vector then remove this value from the vector. You'd then use this index to set the location of the output:
N = 10; %// Length 10 vector
num_vals = 5; %// 5 values to populate
vec = 1 : N; %// Generate vector from 1 up to N
k = zeros(1, N); %// Initialize output k
%// Repeat the following for as many times as num_vals
for idx = 1 : num_vals
%// Obtain a value from the vector
ind = vec(randi(numel(vec), 1));
%// Remove from the vector
vec(ind) = [];
%// Set location in output to 1
k(ind) = 1;
end
The above code should still give you the desired effect, but I would argue that it's less efficient.
i have a vector a = [1; 6; 8]
and want to create a matrix with n columns and size(a,1) rows.
Each i'th row is all zeros but on the a(i) index is one.
>> make_the_matrix(a, 10)
ans =
1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0
use sparse
numCol = 10; % number of colums in output matrix, should not be greater than max(a)
mat = sparse( 1:numel(a), a, 1, numel(a), numCol );
if you want a full matrix just use
full(mat)
Here is my first thought:
a = [1;6;8];
nCols = 10;
nRows = length(a);
M = zeros(nRows,nCols);
M(:,a) = eye(nRows)
Basically the eye is assigned to the right columns of the matrix.
I have the following 5x5 Matrix A:
1 0 0 0 0
1 1 1 0 0
1 0 1 0 1
0 0 1 1 1
0 0 0 0 1
I am trying to find the centroid in MATLAB so I can find the scatter matrix with:
Scatter = A*Centroid*A'
If you by centroid mean the "center of mass" for the matrix, you need to account for the placement each '1' has in your matrix. I have done this below by using the meshgrid function:
M =[ 1 0 0 0 0;
1 1 1 0 0;
1 0 1 0 1;
0 0 1 1 1;
0 0 0 0 1];
[rows cols] = size(M);
y = 1:rows;
x = 1:cols;
[X Y] = meshgrid(x,y);
cY = mean(Y(M==1))
cX = mean(X(M==1))
Produces cX=3 and cY=3;
For
M = [1 0 0;
0 0 0;
0 0 1];
the result is cX=2;cY=2, as expected.
The centroid is simply the mean average computed separately for each dimension.
To find the centroid of each of the rows of your matrix A, you can call the mean function:
centroid = mean(A);
The above call to mean operates on rows by default. If you want to get the centroid of the columns of A, then you need to call mean as follows:
centroid = mean(A, 2);