matlab generate fixed degree undirected graph - matlab

I would like to generate the adjacency matrix of an undirected graph with N nodes.
In particular, this graph should have a fixed degree (each node is connected to a fixed number of node d).
If a set d = N-1, the solution is trivial:
A = ones(N) - eye(N);
How can I generalize it for any d?
ADD:
Here is a solution (thanks to Oli Charlesworth):
function A = fixedDegreeGraph(N, d)
A = zeros(N);
for i=1:N
b = i;
f = i;
for k=1:floor(d/2)
f = f + 1;
if (f == N + 1)
f = 1;
end
A(i, f) = 1;
A(f, i) = 1;
b = b - 1;
if (b == 0)
b = N;
end
A(i, b) = 1;
A(b, i) = 1;
end
end

For even d, here's a way to visualise the approach.
Draw the vertices out arranged in a circle.
Each vertex is connected to its immediate (d/2) left-hand neighbours, and its immediate (d/2) right-hand neighbours.
It should be fairly obvious how to turn this into an adjacency matrix (hint: it will be a circulant matrix, so you may find the toeplitz function useful).
Extending this to odd d is not much harder... (although note there is no solution if both N and d are odd)

Related

Defining a matrix by avoiding the use of for loops

I have a 3D matrix X of size a x b x c.
I want to create a 3D matrix Y in MATLAB as follows:
X = rand(10, 10, 5);
[a, b, c] = size(X);
for i = 1 : c
for j = 1 : a
for k = 1 : b
if j<a && k<b
Y(j, k, i) = X(j+1, k, i) + X(j, k+1, i).^4;
else
Y(j, k, i) = X(a, b, i) + X(a, b, i).^4;
end
end
end
end
How can I do that by avoiding using a lot of for loops? In other words, how can I rewrite the above code in a faster way without using a lot of loops?
Indexing Arrays/Matrices
Below I added a portion to your script that creates an array Z that is identical to array Y by using indexing that covers the equivalent indices and element-wise operations that are indicated by the dot . preceding the operation. Operations such as multiplication * and division / can be specified element-wise as .* and ./ respectively. Addition and subtraction act in the element-wise fashion and do not need the dot .. I also added an if-statement to check that the arrays are the same and that the for-loops and indexing methods give equivalent results. Indexing using end refers to the last index in the corresponding/respective dimension.
Snippet:
Y = zeros(a,b,c);
Y(1:end-1,1:end-1,:) = X(2:end,1:end-1,:) + X(1: end-1, 2:end,:).^4;
Y(end,1:end,:) = repmat(X(a,b,:) + X(a,b,:).^4,1,b,1);
Y(1:end,end,:) = repmat(X(a,b,:) + X(a,b,:).^4,a,1,1);
Full Script: Including Both Methods and Checking
X = rand(10, 10, 5);
[a, b, c] = size(X);
%Initialed for alternative result%
Z = zeros(a,b,c);
%Looping method%
for i = 1 : c
for j = 1 : a
for k = 1 : b
if j < a && k < b
Y(j, k, i) = X(j+1, k, i) + X(j, k+1, i).^4;
else
Y(j, k, i) = X(a, b, i) + X(a, b, i).^4;
end
end
end
end
%Indexing and element-wise method%
Z(1:end-1,1:end-1,:) = X(2:end,1:end-1,:) + X(1: end-1, 2:end,:).^4;
Z(end,1:end,:) = repmat(X(a,b,:) + X(a,b,:).^4,1,b,1);
Z(1:end,end,:) = repmat(X(a,b,:) + X(a,b,:).^4,a,1,1);
%Checking if results match%
if(Z == Y)
fprintf("Matched result\n");
end
Ran using MATLAB R2019b

adaptive elliptical structuring element in MATLAB

I'm trying to create an adaptive elliptical structuring element for an image to dilate or erode it. I write this code but unfortunately all of the structuring elements are ones(2*M+1).
I = input('Enter the input image: ');
M = input('Enter the maximum allowed semi-major axes length: ');
% determining ellipse parameteres from eigen value decomposition of LST
row = size(I,1);
col = size(I,2);
SE = cell(row,col);
padI = padarray(I,[M M],'replicate','both');
padrow = size(padI,1);
padcol = size(padI,2);
for m = M+1:padrow-M
for n = M+1:padcol-M
a = (l2(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
b = (l1(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
if e1(m-M,n-M,1)==0
phi = pi/2;
else
phi = atan(e1(m-M,n-M,2)/e1(m-M,n-M,1));
end
% defining structuring element for each pixel of image
x0 = m;
y0 = n;
se = zeros(2*M+1);
row_se = 0;
for i = x0-M:x0+M
row_se = row_se+1;
col_se = 0;
for j = y0-M:y0+M
col_se = col_se+1;
x = j-y0;
y = x0-i;
if ((x*cos(phi)+y*sin(phi))^2)/a^2+((x*sin(phi)-y*cos(phi))^2)/b^2 <= 1
se(row_se,col_se) = 1;
end
end
end
SE{m-M,n-M} = se;
end
end
a, b and phi are semi-major and semi-minor axes length and phi is angle between a and x axis.
I used 2 MATLAB functions to compute the Local Structure Tensor of the image, and then its eigenvalues and eigenvectors for each pixel. These are the matrices l1, l2, e1 and e2.
This is the bit of your code I didn't understand:
a = (l2(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
b = (l1(m-M,n-M)+eps/l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
I simplified the expression for b to (just removing the indexing):
b = (l1+eps/l1+l2+2*eps)*M;
For l1 and l2 in the normal range we get:
b =(approx)= (l1+0/l1+l2+2*0)*M = (l1+l2)*M;
Thus, b can easily be larger than M, which I don't think is your intention. The eps in this case also doesn't protect against division by zero, which is typically the purpose of adding eps: if l1 is zero, eps/l1 is Inf.
Looking at this expression, it seems to me that you intended this instead:
b = (l1+eps)/(l1+l2+2*eps)*M;
Here, you're adding eps to each of the eigenvalues, making them guaranteed non-zero (the structure tensor is symmetric, positive semi-definite). Then you're dividing l1 by the sum of eigenvalues, and multiplying by M, which leads to a value between 0 and M for each of the axes.
So, this seems to be a case of misplaced parenthesis.
Just for the record, this is what you need in your code:
a = (l2(m-M,n-M)+eps ) / ( l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
b = (l1(m-M,n-M)+eps ) / ( l1(m-M,n-M)+l2(m-M,n-M)+2*eps)*M;
^ ^
added parentheses
Note that you can simplify your code by defining, outside of the loops:
[se_x,se_y] = meshgrid(-M:M,-M:M);
The inner two loops, over i and j, to construct se can then be written simply as:
se = ((se_x.*cos(phi)+se_y.*sin(phi)).^2)./a.^2 + ...
((se_x.*sin(phi)-se_y.*cos(phi)).^2)./b.^2 <= 1;
(Note the .* and .^ operators, these do element-wise multiplication and power.)
A further slight improvement comes from realizing that phi is first computed from e1(m,n,1) and e1(m,n,2), and then used in calls to cos and sin. If we assume that the eigenvector is properly normalized, then
cos(phi) == e1(m,n,1)
sin(phi) == e1(m,n,2)
But you can always make sure they are normalized:
cos_phi = e1(m-M,n-M,1);
sin_phi = e1(m-M,n-M,2);
len = hypot(cos_phi,sin_phi);
cos_phi = cos_phi / len;
sin_phi = sin_phi / len;
se = ((se_x.*cos_phi+se_y.*sin_phi).^2)./a.^2 + ...
((se_x.*sin_phi-se_y.*cos_phi).^2)./b.^2 <= 1;
Considering trigonometric operations are fairly expensive, this should speed up your code a bit.

Gramm Schmidt QR factorisation doesn't return Q and R correctly

I have implemented a MATLAB function for Gramm-Schmidt QR factorisation. Q's inverse should be equal to it's inverse, but it's not, and I can't see why. I even tried with somebody else's function, which is identical, and the result was the same. This is my function:
function [Q R] = gramschmidt(A)
[n n] = size(A);
for i = 1:n
R(i,i) = norm( A(:, i) );
Q(:, i) = A(:, i) / R ( i, i);
for j = i + 1 : n
R(i, j) = Q(:, i)' * A(:, j);
A(:, j) = A(:, j) - Q(:, i) * R(i, j);
end
end
end
`
Firstly, I think what you meant to say is Q's conjugate transpose should be equal to it's inverse, i.e. that it is a unitary matrix.
Secondly, what makes you think that Q returned by your function is not unitary? Let's check.
A = randn(20,20);
[Q, R] = gramschmidt(A);
diff = #(X,Y) max(abs(X(:)-Y(:))); % element-wise max abs difference
diff(Q'*Q, eye(size(A)))
ans =
1.7764e-15
As you can see, it is unitary to a very good precision.
Also, just in case, Matlab has a built-in and efficient qr function that performs this decomposition, which also handles rectangular matrices, not just square ones like your implementation.

How to find an arbitrary perpendicular vector of another vector in MATLAB?

I need to create arbitrary perpendicular vector n with components (a, b, c) to another known vector k with components (x,y,z).
The following code creates arbitrary vector n, but I need random numbers for components in the range [-inf, inf] how can I acheive that? (because otherwise vector components created may not exceed some value in given case 10^11 ) Or maybe concept "arbitrary vector" does not require that?
function [a,b,c] = randomOrghogonalVector(x,y,z)
a = 0;
b = 0;
c = 0;
randomDistr = rand * 10^11 * 2 - 10^11; % issue 1
% excluding trivial solution
if x == 0 && y == 0 && z ==0
a = NaN; b = a; c = a;
else
if z ~=0
a = randomDistr;
b = randomDistr;
c = - (x * a + b * y ) / z;
else
if z == 0 && x ~= 0
c = randomDistr;
b = randomDistr;
a = - (z * c + b * y ) / x;
else
if z == 0 && x == 0 && y ~= 0
c = randomDistr;
a = randomDistr;
b = - (z * c + a * x ) / y;
end
end
end
end
The easiest solution I see is to first find a random vector that is orthogonal to your original vector, and then give it a random length. In Matlab, this can be done by defining the following function
function [a, b, c] = orthoVector(x, y, z)
xin = [x;y;z];
e = xin;
while ((e'*xin)==xin'*xin)
e = 2.*rand(3,1)-1;
end
xout = cross(xin, e);
xout = 1.0/(rand()) * xout;
a = xout(1);
b = xout(2);
c = xout(3);
end
Line-by-line, here's what I'm doing:
you asked for this format [a,b,c] = f(x,y,z). I would recommend using function xout = orthoVector(xin), which would make this code even shorter.
Since Matlab handles vectors best as vectors, I'm creating vector xin.
e will be one random vector, different from xin used to compute the orthogonal vector. Since we're dealing with random vectors, we initialize it to be equal to xin.
For this algorithm to work, we need to make sure that e and xin are pointing in different directions. Until this is the case...
...create a new random vector e. Note that rand will give values between 0 and 1. Thus, each component of e will be between -1 and 1.
Ok, if we end, e and xin are pointing in different directions
Our vector xout will be orthogonal to xin and e.
Let's multiply vector xout by a random number between 1 and "very large"
a is first component of xout
b is second component of xout
c is third component of xout
all done.
Optional: if you want to have very large vectors, you could replace line 8 by
xout = exp(1./rand())/(rand()) * xout;
This will give you a very large spread of values.
Hope this helps, cheers!

How to avoid nested for loops in Matlab for better cpu time

I should calculate this formula for large value of p, so 4 nested loops made my code very slow and inapplicable. I will so thankful if anyone can help me for better implementation with use of sum and other suitable matlab commands!
K(i,j)=sum(sum(a(m)*b(n)*A(i,j,m,n),m=1:p),n=1:p);
i,j,m,n ->1:p
and A is 4D Matrix and a,b are vector.
Thank.
I can get rid of 2 of the for loops. Perhaps one of the MATLAB wizards on this site can do better.
p = 3;
A = rand(p, p, p, p)
a = rand(p, 1)
b = rand(p, 1)
% I think your original code does something like this.
K1 = zeros(p, p);
for n = 1: p
for m = 1: p
for j = 1: p
for i = 1: p
K1(i, j) = K1(i, j) + a(m) * b(n) * A(i, j, m, n);
end
end
end
end
K1
% This gives the same result, with half the loops.
K2 = zeros(p, p);
for n = 1: p
for m = 1: p
K2 = K2 + a(m) * b(n) * A(:,:,m,n);
end
end
K2
% Verify that the two answers are the same.
all(K1(:) == K2(:))