Generating random matrix in MATLAB - matlab

I would like to generate 100 random matrices A=[a_{ij}] of size 6 by 6 in (0, 9) using matlab programming satisfying the following properties:
1. multiplicative inverse: i.e., a_{ij}=1/a_{ji} for all i,j=1,2,...,6.
2. all entries are positive: i.e., a_{ij}>0 for all i,j=1,2,...,6.
3. all diagonal elements are 1: i.e., a_{ii}=1 for all i=1,2,..,6.
4. transitive: i.e., a_{ih}*a_{hj}=a_{ij} for all i,j,h=1,2,...,6.
So far, I tried to use a matlab function rand(6)*9. But, I got wrong matrices. I was wondering if anyone could help me?
Here is my matlab code:
clc; clear;
n=6;
m=0;
for i=1:n
for j=1:n
for h=1:n
while m<100 % generate 100 random matrices
A=rand(n)*9; % random matrix in (0,9)
A(i,j)>0; % positive entries
A(i,j)==1/A(j,i); % multiplicative inverse
A(i,h)*A(h,j)==A(i,j); % transitive
if i==j && j==h
A(i,j)==1; % diagonal elements are 1
break;
end
m=m+1;
M{m}=A
end
end
end
end
M{:}

clear; clc
M = cell(1, 100); % preallocate memory
% matrix contains both x & 1/x
% we need a distribution whose multiplication with its inverse is uniform
pd = makedist('Triangular', 'a', 0, 'b', 1, 'c', 1);
for m=1:100 % 100 random matrices
A = zeros(6); % allocate memory
% 5 random numbers for 6x6 transitive random matrix
a = random(pd, 1, 5);
% choose a or 1/a randomly
ac = rand(1, 5) < 0.5;
% put these numbers above the diagonal
for i=1:5
if ac(i)
A(i, i+1) = a(i);
else
A(i, i+1) = 1 / a(i);
end
end
% complete the transitivity going above
for k=flip(1:4)
for i=1:k
A(i, i-k+6) = A(i, i-k+5) * A(i-k+5, i-k+6);
end
end
% lower triangle is multiplicative inverse of upper triangle
for i=2:6
for j=1:i-1
A(i,j) = 1 / A(j,i);
end
end
c = random(pd); % triangular random variable between (0,1)
A = A ./ max(A(:)) * 9 * c; % range becomes (0, 9*c)
% diagonals are 1
for i=1:6
A(i,i) = 1;
end
% insert the result
M{m} = A;
end
There are actually 5 numbers are independent in 6x6 transitive matrix. The others are derived from them as shown in the code.
The reason why triangular distribution is used for these numbers is because pdf of triangular distribution is f(x)=x, and pdf of inverse triangular distribution is f-1(x)=1/x; thus their multiplication becomes uniform distribution. (See pdf of inverse distribution)
A = A ./ max(A(:)) * 9; makes the range (0,9), but there will always be 9 as the maximum element. We need to shrink the result by a random coefficient to obtain the result uniformly distributed in (0,9). Since A is uniformly distributed, we can achieve this again by triangular distribution. (See product distribution)
Another solution to the range issue would be calculating A while its maximum is above 9. This would eliminate the latter problem.
Since all elements of A depends on 5 random variables, the distribution of them will never be perfectly uniform, but the aim here is to maintain a reasonable scale for them.

It took me a litte to think about your question, but I realized there is no solution.
You require your elements of A to be uniformly distributed in the (0,9) range. You also require a_{ij}*a_{jk}=a_{ik}. Since the product of two uniform distributions is not a unifrom distribution, there is no solution to your question.

Related

Matlab: 2D Discrete Fourier Transform and Inverse

I'm trying to run a program in matlab to obtain the direct and inverse DFT for a grey scale image, but I'm not able to recover the original image after applying the inverse. I'm getting complex numbers as my inverse output. Is like i'm losing information. Any ideas on this? Here is my code:
%2D discrete Fourier transform
%Image Dimension
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1)=(1/M*N)*F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N)));
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
There are a couple of issues with your code:
You are not applying the definition of the DFT (or IDFT) correctly: you need to sum over the original variable(s) to obtain the transform. See the formula here; notice the sum.
In the IDFT the normalization constant should be 1/(M*N) (not 1/M*N).
Note also that the code could be made mucho more compact by vectorization, avoiding the loops; or just using the fft2 and ifft2 functions. I assume you want to compute it manually and "low-level" to verify the results.
The code, with the two corrections, is as follows. The modifications are marked with comments.
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
F = zeros(M,N); % initiallize to 0
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1) = F(u+1,v+1) + ...
f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N))); % add term
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
z = zeros(M,N);
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1) = z(x+1,y+1) + (1/(M*N)) * ... % corrected scale factor
F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N))); % add term
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
Now the original and recovered image differ only by very small values, of the order of eps, due to the usual floating-point inaccuacies:
>> f-z
ans =
1.0e-15 *
Columns 1 through 2
0.180411241501588 + 0.666133814775094i -0.111022302462516 - 0.027755575615629i
0.000000000000000 + 0.027755575615629i 0.277555756156289 + 0.212603775716506i
0.000000000000000 - 0.194289029309402i 0.000000000000000 + 0.027755575615629i
Column 3
-0.194289029309402 - 0.027755575615629i
-0.222044604925031 - 0.055511151231258i
0.111022302462516 - 0.111022302462516i
Firstly, the biggest error is that you are computing the Fourier transform incorrectly. When computing F, you need to be summing over x and y, which you are not doing. Here's how to rectify that:
F = zeros(M, N);
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=F(u+1,v+1) + f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Secondly, in the inverse transform, your bracketing is incorrect. It should be 1/(M*N) not (1/M*N).
As an aside, at the cost of a bit more memory, you can speed up the computation by not nesting so many loops. Namely, when computing the FFT, do the following instead
x = (1:1:M)'; % x is a column vector
y = (1:1:N) ; % y is a row vector
for u = 0:1:M-1
for v = 0:1:N-1
F2(u+1,v+1) = sum(f .* exp(-2i * pi * (u*(x-1)/M + v*(y-1)/N)), 'all');
end
end
To take this method to the extreme, i.e. not using any loops at all, you would do the following (though this is not recommended, since you would lose code readability and the memory cost would increase exponentially)
x = (1:1:M)'; % x is in dimension 1
y = (1:1:N) ; % y is in dimension 2
u = permute(0:1:M-1, [1, 3, 2]); % x-freqs in dimension 3
v = permute(0:1:N-1, [1, 4, 3, 2]); % y-freqs in dimension 4
% sum the exponential terms in x and y, which are in dimensions 1 and 2.
% If you are using r2018a or older, the below summation should be
% sum(sum(..., 1), 2)
% instead of
% sum(..., [1,2])
F3 = sum(f .* exp(-2i * pi * (u.*(x-1)/M + v.*(y-1)/N)), [1, 2]);
% The resulting array F3 is 1 x 1 x M x N, to make it M x N, simply shiftdim or squeeze
F3 = squeeze(F3);

Generating random diagonally dominant dense/sparse matrices in matlab

Is there a matlab command for generating a random n by n matrix, with elements taken in the interval [0,1], with x% of the entries on the off-diagonal to be 0. Then, additionally setting the element in the diagonal to be the sum of every element in its respective column? In order to create a diagonally dominant dense/sparse matrix? This may be easy enough to write a code for but I was wondering if there was already a built in function with this capability.
EDIT:
I am new to Matlab/programming so this was an easier said than done. I'm having trouble making the matrix with the percentage ignoring the diagonal. It's a n x n matrix, so there are $n^2$ entries, with n of them on the diagonal, I want the percentage of zeros to be taken from $n^2 - n$ elements, i.e. all the off-diagonal elements. I cannot implement this correctly. I do not know how to initialize my M (see below) to correspond correctly.
% Enter percentage as a decimal
function [M] = DiagDomSparse(n,x)
M = rand(n);
disp("Original matrix");
disp(M);
x = sum(M);
for i=1:n
for j=1:n
if(i == j)
M(i,j) = x(i);
end
end
end
disp(M);
Here is one approach that you could use. I'm sure you will get some other answers now with a more clever approach, but I like to keep things simple and understandable.
What I'm doing below is creating the data to be put in the off-diagonal elements first. I create an empty matrix and copy this data into the off-diagonal elements using linear indexing. Now I can compute the sum of columns and write those into the diagonal elements using linear indexing again. Because the matrix was initialized to zero, the diagonal elements are still zero when I compute the sum of columns, so they don't interfere.
n = 5;
x = 0.3; % fraction of zeros in off-diagonal
k = round(n*(n-1)*x); % number of zeros in off-diagonal
data = randn(n*(n-1)-k,1); % random numbers, pick your distribution here!
data = [data;zeros(k,1)]; % the k zeros
data = data(randperm(length(data))); % shuffle
diag_index = 1:n+1:n*n; % linear index to all diagonal elements
offd_index = setdiff(1:n*n,diag_index); % linear index to all other elements
M = zeros(n,n);
M(offd_index) = data; % set off-diagonal elements to data
M(diag_index) = sum(M,1); % set diagonal elements to sum of columns
To refer to the diagonal you want eye(n,'logical'). Here is a solution:
n=5;
M = rand(n);
disp("Original matrix");
disp(M);
x = sum(M);
for i=1:n
for j=1:n
if(i == j)
M(i,j) = x(i);
end
end
end
disp('loop solution:')
disp(M);
M(eye(n,'logical'))=x;
disp('eye solution:')
disp(M);

Plot a matrix in graph with two axis in matlab

I need to plot a NxN matrix 'M' full of zeros, but only show the cases where m(x,y) is different from 0.
t_max = 10; % set the maximum number of iterations
n = 10; % dimension n*n
d = 1; % the probability of changing place
x = randi([1 n]); % random row
y = randi([1 n]); % random column
grid = zeros(10); % set an empty gride n*n
grid(x,y) = 1; % put an agent in a random place
for t=1:t_max
newgrid = randomwalk1(grid,d); % call the function random walk for one agent
end
I tried image(m) but it's not giving satisfying results since I need also to keep track of the element that is different to 0, hold on doesn't work in this case.
You are looking for the spy() function. Just type spy(m) and see what happens.

I need to spectral clustering for two donuts shape dataset.(Matlab)

I have tried hours but I cannot find solution.
I have "two Donuts" Data sample (variable "X")
you can download file below link
donut dataset(rings.mat)
which spreads to 2D shape like below image
First 250pts are located inside donuts and last 750 pts are located outside donuts.
and I need to perform spectral clustering.
I made (similarity matrix "W") with Gaussian similarity distance.
and I made degree matrix by sum of each raw of "W"
and then I computed eigen value(E) and eigen Vector(V)
and the shape of "V" is not good.
what is wrong with my trial???
I cannot figure out.
load rings.mat
[D, N] = size(X); % data stored in X
%initial plot data
figure; hold on;
for i=1:N,
plot(X(1,i), X(2,i),'o');
end
% perform spectral clustering
W = zeros(N,N);
D = zeros(N,N);
sigma = 1;
for i=1:N,
for j=1:N,
xixj2 = (X(1,i)-X(1,j))^2 + (X(2,i)-X(2,j))^2 ;
W(i,j) = exp( -1*xixj2 / (2*sigma^2) ) ; % compute weight here
% if (i==j)
% W(i,j)=0;
% end;
end;
D(i,i) = sum(W(i,:)) ;
end;
L = D - W ;
normL = D^-0.5*L*D^-0.5;
[u,s,v] = svd(normL);
If you use the Laplacian like it is in your code (the "real" laplacian), then to cluster your points into two sets you will want the eigenvector corresponding to second smallest eigenvalue.
The intuitive idea is to connect all of your points to each other with springs, where the springs are stiffer if the points are near each other, and less stiff for points far away. The eigenvectors of the Laplacian are the modes of vibration if you hit your spring network with a hammer and watch it oscillate - smaller eigenvalues corresponding to lower frequency "bulk" modes, and larger eigenvalues corresponding to higher frequency oscillations. You want the eigenvalue corresponding to the second smallest eigenvalue, which will be like the second mode in a drum, with a positive clustered together, and negative part clustered together.
Now there is some confusion in the comments about whether to use the largest or smallest eigenvalue, and it is because the laplacian in the paper linked there by dave is slightly different, being the identity minus your laplacian. So there they want the largest ones, whereas you want the smallest. The clustering in the paper is also a bit more advanced, and better, but not as easy to implement.
Here is your code, modified to work:
load rings.mat
[D, N] = size(X); % data stored in X
%initial plot data
figure; hold on;
for i=1:N,
plot(X(1,i), X(2,i),'o');
end
% perform spectral clustering
W = zeros(N,N);
D = zeros(N,N);
sigma = 0.3; % <--- Changed to be smaller
for i=1:N,
for j=1:N,
xixj2 = (X(1,i)-X(1,j))^2 + (X(2,i)-X(2,j))^2 ;
W(i,j) = exp( -1*xixj2 / (2*sigma^2) ) ; % compute weight here
% if (i==j)
% W(i,j)=0;
% end;
end;
D(i,i) = sum(W(i,:)) ;
end;
L = D - W ;
normL = D^-0.5*L*D^-0.5;
[u,s,v] = svd(normL);
% New code below this point
cluster1 = find(u(:,end-1) >= 0);
cluster2 = find(u(:,end-1) < 0);
figure
plot(X(1,cluster1),X(2,cluster1),'.b')
hold on
plot(X(1,cluster2),X(2,cluster2),'.r')
hold off
title(sprintf('sigma=%d',sigma))
Here is the result:
Now notice that I changed sigma to be smaller - from 1.0 to 0.3. When I left it at 1.0, I got the following result:
which I assume is because with sigma=1, the points in the inner cluster were able to "pull" on the outer cluster (which they are about distance 1 away from) enough so that it was more energetically favorable to split both circles in half like a solid vibrating drum, rather than have two different circles.

matlab -- use of fminsearch with matrix

If I have a function for example :
k=1:100
func=#(s) sum(c(k)-exp((-z(k).^2./s)))
where c and z are matrices with same size (for example 1x100) , is there any way to use fminsearch to find the "s" value?
fminsearch needs an initial condition in the second parameter, not boundary conditions (though some of the options may support boundaries).
Just call
fminsearch(func,-0.5)
Where you saw examples passing in a vector, was a multidimensional search across multiple coefficients, and the vector was the initial value of each coefficient. Not limits on the search space.
You can also use
fminbnd(func, -0.5, 1);
which performs constrained minimization.
But I think you should minimize the norm of the error, not the sum (minimizing the sum leads to a large error magnitude -- very very negative).
If you have the Optimization Toolbox, then lsqnonlin could be useful.
I guess you would like to find argmin of your symbolic function, use
Index of max and min value in an array
OR
ARGMAX/ARGMIN by Marco Cococcioni:
function I = argmax(X, DIM)
%ARGMAX Argument of the maximum
% For vectors, ARGMAX(X) is the indix of the smallest element in X. For matrices,
% MAX(X) is a row vector containing the indices of the smallest elements from each
% column. This function is not supported for N-D arrays with N > 2.
%
% It is an efficient replacement to the use of [Y,I] = MAX(X,[],DIM);
% See ARGMAX_DEMO for a speed comparison.
%
% I = ARGMAX(X,DIM) operates along the dimension DIM (DIM can be
% either 1 or 2).
%
% When complex, the magnitude ABS(X) is used, and the angle
% ANGLE(X) is ignored. This function cannot handle NaN's.
%
% Example:
% clc
% disp('If X = [2 8 4; 7 3 9]');
% disp('then argmax(X,1) should be [2 1 2]')
% disp('while argmax(X,2) should be [2 3]''. Now we check it:')
% disp(' ');
% X = [2 8 4;
% 7 3 9]
% argmax(X,1)
% argmax(X,2)
%
% See also ARGMIN, ARGMAXMIN_MEX, ARGMAX_DEMO, MIN, MAX, MEDIAN, MEAN, SORT.
% Copyright Marco Cococcioni, 2009.
% $Revision: 1.0 $ $Date: 2009/02/16 19:24:01$
if nargin < 2,
DIM = 1;
end
if length(size(X)) > 2,
error('Function not provided for N-D arrays when N > 2.');
end
if (DIM ~=1 && DIM ~= 2),
error('DIM has to be either 1 or 2');
end
if any(isnan(X(:))),
error('Cannot handle NaN''s.');
end
if not(isreal(X)),
X = abs(X);
end
max_NOT_MIN = 1; % computes argmax
I = argmaxmin_mex(X, DIM, max_NOT_MIN);