Adjacency matrix of a network to Distance matrix (Two -Hop) - matlab

I have the following code for generating an adjacency matrix for a network.
How do I go about creating a distance matrix (Probably a two hop matrix)from this output.
function adj = AdjMatrixLattice4( N, M )
% Size of adjacency matrix
MN = M*N;
adj = zeros(MN,MN);
for i=1:N
for j=1:N
A = M*(i-1)+j; %Node # for (i,j) node
if(j<N)
B = M*(i-1)+j+1; %Node # for node to the right
C = M*(i-1)+j+2;
D = M*(i-1)+j+2;
adj(A,B) = 1;
adj(B,A) = 1;
adj(A,C) = 1;
adj(C,A) = 1;
adj(A,D) = 1;
adj(D,A) = 1;
end
if(i<M)
B = M*i+j;
C = M*i+j+1; %Node # for node below
D = M*i+j;
adj(A,B) = 1;
adj(B,A) = 1;
adj(A,C) = 1;
adj(C,A) = 1;
adj(A,D) = 1;
adj(D,A) = 1;
end
end
end
end
The output for the following program is
AdjMatrixLattice4(3,3)
ans =
0 1 1 1 1 0 0 0 0 0
1 0 1 1 1 1 0 0 0 0
1 1 0 0 0 1 1 0 0 0
1 1 0 0 1 1 1 1 0 0
1 1 0 1 0 1 1 1 1 0
0 1 1 1 1 0 0 0 1 1
0 0 1 1 1 0 0 1 1 0
0 0 0 1 1 0 1 0 1 1
0 0 0 0 1 1 1 1 0 0
0 0 0 0 0 1 0 1 0 0

Related

elimination of consecutive regions

I need to effectively eliminate consecutive regions in vector "a" or better in rows/columns of matrix "A" with length of separate ones regions greater than positive integer N <= length(A):
See following example:
N = 2 % separate consecutive regions with length > 2 are zeroed
a = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
a_elim = [0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1]
or 2D case:
N = 2
A = [1 0 1 …
1 1 0 …
1 1 0 …
0 0 1 …
1 1 1]
% elimination over columns
A_elim= 0 0 1
0 1 0
0 1 0
0 0 1
1 1 1
% elimination over rows
A_elim= 1 0 1
1 1 0
1 1 0
0 0 1
0 0 0
I am looking for effective vectorized MATLAB function performing this task for size(A) ~ [100000, 1000] (over columns case).
You can use a convolution:
For the 1D case:
N = 2 %tolerance
A = [0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1]
ind = conv(A,ones(N+1,1),'same');
%ind = 1 2 2 1 1 2 3 2 1 1 2 3 3 2 2 1
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
ind = conv(ind>N,ones(N+1,1),'same')>0;
%ind = 0 0 0 0 0 1 1 1 0 0 1 1 1 1 0 0
%A = 0 1 1 0 0 1 1 1 0 0 1 1 1 1 0 1
A(ind) = 0
if N is odd you need an extra step:
ind = conv(A,ones(N+1,1),'same');
ind(find(ind==N+1)+1) = N+1 %the extra step
ind = conv(ind>N,ones(N+1,1),'same')>0;
Generalization for nD dimension:
N = 3 %tolerance
A = round(rand(5,5,5));
for ii = 1:ndims(A)
conv_vec = permute(ones(N+1,1),circshift([1:ndims(A)],ii-1,2))
ind = convn(A,conv_vec,'same')
if mod(N,2) == 1
ind(find(ind==N+1)+1) = N+1
end
ind = convn(ind>N,conv_vec,'same')>0
X = A;
X(ind) = 0
end

Filter islands based on length in a binary array - MATLAB

I have a binary array and I would like to flip values based on the length which they repeat. as an example
Ar = [0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
Ideally I would like to flip the 1's which repeat only 2 or fewer times resulting in the following.
Ar = [0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
From what I have located online, the Diff function is most commenly used to locate and remove sequences. But from what I have located, it appears to target all instances.
Simply use imopen from Image Processing toolbox with a kernel of 3 ones -
imopen(Ar,[1,1,1])
Sample run -
>> Ar = [0 1 0 0 0 1 1 0 0 0 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1];
>> out = imopen(Ar,[1,1,1]);
>> [Ar(:) out(:)]
ans =
0 0
1 0
0 0
0 0
0 0
1 0
1 0
0 0
0 0
0 0
1 1
1 1
1 1
1 1
1 1
0 0
0 0
0 0
0 0
1 1
1 1
1 1
1 1
1 1
1 1
Vectorized solution without using I.P. toolbox -
function out = filter_islands_on_length(Ar, n)
out = Ar;
a = [0 Ar 0];
d = diff(a);
r = find(d);
s0 = r(1:2:end);
s1 = r(2:2:end);
id_arr = zeros(1,numel(Ar));
m = (s1-s0) <= n;
id_arr(s0(m)) = 1;
id_arr(s1(m)) = -1;
out(cumsum(id_arr)~=0) = 0;
Sample runs -
>> Ar
Ar =
0 1 0 0 0 1 1 0 0 0 1 1 1
>> filter_islands_on_length(Ar, 2)
ans =
0 0 0 0 0 0 0 0 0 0 1 1 1
>> filter_islands_on_length(Ar, 1)
ans =
0 0 0 0 0 1 1 0 0 0 1 1 1
Another solution requiring no toolbox but needs Matlab 2016a or later:
n = 3; % islands shorter than n will be removed
Ar = movmax(movsum(Ar,n),[ceil(n/2-1) floor(n/2)])==n;

Using vectorization instead of a 'for Loop' in Matlab

I have a set of 32 bits binary values incoming from a sensor. I have to form all the possible combinations of these values and then convert them into a decimal value.
The code slows down terribly if the incoming rows are more that 80000 - 90000. It takes 120 minutes to run.
I want to optimize this code, since 3 For loops and a function within the innermost loop is slowing down my algorithm. Is there any chance that I can eliminate some For loops and substitute them with vectorizing to speed up the process.
b1 = [0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b2 = [0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b3 = [0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];
b4 = [0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1];
b5 = [0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1];
FullVector = [b1;b2;b3;b4;b5];
for Idx = 1:size(FullVector,1)
k = 1;
MinLength = 4;
MaxLength = 8;
StepSize = 2;
for StartByte = 1:8
for StartBit = 1:8
for SignalLength = MinLength:StepSize:MaxLength
DecimalVals.s(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
k = k+1;
end
end
end
end
The function:
function decimal = BitCombinations(ByteArray,Sbyte,Sbit,lengthSignal)
%function extracts the required bits from a byte array and
%returns the decimal equivalent of the bits.
%Inputs:
%Sbyte - Starting byte
%Sbit - Starting bit in the given byte
%length - length of bits to be extracted
%Output:
%dec - Returns the dec
startbit_pos = ((Sbyte-1)*8+Sbit);
endbit_pos = ((Sbyte-1)*8+Sbit+lengthSignal-1);
if endbit_pos <= 64
extractedbits = ByteArray(startbit_pos:endbit_pos);
extractedbits = fliplr(extractedbits);
decimal = bi2de(extractedbits);
else
decimal = NaN;
end
end
you should preallocate your result matrix DecimalVals by using the following code example:
b1 = repmat([0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b2 = repmat([0 1 0 1 0 1 1 1 1 1 1 0 1 1 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b3 = repmat([0 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);
b4 = repmat([0 1 0 1 0 1 1 1 1 1 0 1 1 0 0 1 0 0 1 0 1 0 0 0 0 1 0 0 1 0 0 1],10000,1);
b5 = repmat([0 1 0 1 1 1 1 0 1 1 0 1 1 1 0 1 1 0 1 0 1 0 0 1 0 1 0 0 1 0 0 1],10000,1);
FullVector = [b1;b2;b3;b4;b5];
MinLength = 4;
MaxLength = 8;
StepSize = 2;
% Preallocation of the result struct
noOfValues = (((MaxLength - MinLength) / 2) + 1) * MaxLength * MaxLength;
DecimalVals = zeros(size(FullVector,1),noOfValues);
for Idx = 1:size(FullVector,1)
k = 1;
for StartByte = 1:MaxLength
for StartBit = 1:MaxLength
for SignalLength = MinLength:StepSize:MaxLength
DecimalVals(Idx,k) = BitCombinations(FullVector,StartByte,StartBit,SignalLength);
k = k+1;
end
end
end
end
result (on my machine):
time consumption without preallocation: 560 seconds
time consumption WITH preallocation: 300 seconds
Furthermore, please use the MATLAB Profiler (Starting the script by using "Run and Time") to identify the bottleneck, respectively which function takes most time and add the function/line to your question.
Unfortunately, I've got no access to the functions of the Communication System Toolbox, so I used the function bi2de from the File Exchange. In this version, there is one sort of error checking, which takes a lot of time: ~230 seconds
Another thing you could do, besides pre-allocating your array, is to not use fliplr. Take a look at this code snippet
tic
N = 10000;
A = [1:N];
for i = 1:N/2
b = A(N-i+1:-1:i);
end
toc
b = [];
tic
for i = 1:N/2
b = fliplr(A(i:N-i+1));
end
toc
Elapsed time is 0.060007 seconds.
Elapsed time is 0.118267 seconds.
So fliplr is around 2x slower to use, rather than simply use "backwards" indexing. I'm pretty sure you would have something to gain also by making your own bi2de function that is specific to your problem.
I made an attempt on this, haven't checked it for efficiency though, but maybe you can use it for your purposes
function values = myBi2Dec(byte,signalLengths)
persistent indexes
if isempty(indexes)
% Find the matrix indexes for this
indexes = [];
for iBit = 1:8
for iSL = signalLengths
if iBit+iSL-1<=8
indexes = [indexes;sub2ind([8,8],iBit,iBit+iSL-1)];
end
end
end
end
% Lets get the cumulative value
cumB2D = cumBi2Dec(byte);
% We already calculated their position, so simply return them
values = cumB2D(indexes);
function cumB2D = cumBi2Dec(byte)
persistent B2D
if isempty(B2D)
B2D = zeros(8,8);
tmp = 2.^[0:7];
for i = 1:8
B2D(i,i:8) = tmp(1:8-(i-1));
end
end
cumB2D = cumsum(repmat(fliplr(byte),8,1).*B2D,2);
Then try, for example, myBi2Dec([0,0,0,0,1,1,1,1],[4:2:8])

How to create a diamond filled with one in the middle of a matrix?

I know the code below :
N = 5;
assert(N>1 && mod(N,2)==1);
A = zeros(N);
% diamond mask
N2 = fix(N/2);
[I,J] = meshgrid(-N2:N2);
mask = (abs(I) + abs(J)) == N2;
% fill with zeros
A(mask) = 1;
which transforms matrix A to this:
A=
0 0 1 0 0
0 1 0 1 0
1 0 0 0 1
0 1 0 1 0
0 0 1 0 0
But I want the diamond to be filled with 1.
What should I do?
Here's a vectorized approach using bsxfun -
Nh = (N+1)/2;
range_vec = [1:Nh Nh-1:-1:1];
out = bsxfun(#plus,range_vec(:),range_vec) > Nh
Sample runs -
1) N = 5 :
out =
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
2) N = 9 :
out =
0 0 0 0 1 0 0 0 0
0 0 0 1 1 1 0 0 0
0 0 1 1 1 1 1 0 0
0 1 1 1 1 1 1 1 0
1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 0
0 0 1 1 1 1 1 0 0
0 0 0 1 1 1 0 0 0
0 0 0 0 1 0 0 0 0
You can use tril and flip functions:
mat = tril(ones(N), round((N-1)/2)) - tril(ones(N), round((-N-1)/2));
out = mat & flip(mat)
Odd values of N:
% N = 5;
out =
0 0 1 0 0
0 1 1 1 0
1 1 1 1 1
0 1 1 1 0
0 0 1 0 0
Even values of N:
% N = 4;
out =
0 1 1 0
1 1 1 1
1 1 1 1
0 1 1 0
What you need is to return a 1 or a 0 based on the Manhattan distance from each array location to the center of your diamond
N = 5;
assert(N>1 && mod(N,2)==1);
A = false(N);
[m, n] = size(A); %dimensions of A
X = floor([m, n]/2); %floored division gives integer indices of center of array
x = X(1); y = X(2);
radius = m/2; %half the height gives the radius
for a = 1 : m
for b = 1 : n
A(a,b) = abs(a-x)+abs(b-y) <= radius; %test if manhatten distance <= radius
end
end
This naturally will need editing to suit your particular case... In particular, the center of your diamond can realistically be placed anywhere by modifying x, y, and the radius can be either smaller or larger than half the width of the array if you so choose.
Just add a for loop and fill all diagonals:
N = 5;
assert(N>1 && mod(N,2)==1);
A = zeros(N);
% diamond mask
N2 = fix(N/2);
[I,J] = meshgrid(-N2:N2);
for id = 0:N2
A((abs(I) + abs(J)) == id) = 1;
end

Create a Function which returns -1 for empty matrix, 0 for scalar, 1 for vector, 2 for none of these

I am not allowed to use isempty, isscalar, or isvector.
My code is :
function a = classify(x)
b = sum(x(:));
c = sum(b);
if c == 0
a = -1;
elseif length(x) == 1
a = 0;
elseif length(x) > 1
a = 1;
else
a = 2;
end
I am getting error with input :
0 1 0 0 0 1 1
1 0 0 1 1 0 0
1 1 0 0 1 1 1
0 1 1 1 1 1 0
0 1 0 1 0 1 0
1 0 0 1 1 1 1
0 1 0 0 0 0 1
Output for above input is 1
My Auto grader is giving the following error:
Feedback: Your function made an error for argument(s) [0 1 0 0 0 1 1;1 0 0 1 1 0 0;1 1 0 0 1 1 1;0 1 1 1 1 1 0;0 1 0 1 0 1 0;1 0 0 1 1 1 1;0 1 0 0 0 0 1]
Your solution is not correct.
If you are allowed to use size, then a possible solution is
function R = classify(data)
S = size(data);
if any(S == 0) % There is at least one dimension that is zero
R = -1;
elseif all(S == 1) % All dimensions are equal to 1
R = 0;
elseif sum(~(S == 1)) == 1 % There is exactly one dimension that contains more than 1 element
R = 1;
else % There are more than 1 dimensions with more than 1 element
R = 2;
end
end