I recognized this is a quite hard problem for me. I asked this problem on official Matlab side but no-one could help me either so maybe someone of you can come up with an outstanding approach.
In detail my Problem consist of:
N = 100 %some number
G = 21 %random guess < N
for x = 1:N;
a = mod(G^x,N);
end
Now I want the calculation of a to stop, if a number repeats.
For example: a = 1, 2, 3, 1 -break
Seems simple but I just can't handle it right after many tries.
For instance I've put:
for x = 1:N
a = mod(G^x,N);
b = unique(a);
if a ~= b
break
end
end
but doesn't seem to work bc. it's not element wise I guess.
This approach keeps a running log of the past Results and uses the ismember() function to check if the current value of a has been previously seen.
clc;
N = 100; %some number
G = 21; %random guess < N
Results = NaN(1,N);
for x = 1:N
a = mod(G^x,N);
disp(a);
if ismember(a,Results)
disp("-break");
break
end
Results(x) = a;
end
Ran using MATLAB R2019b
I have some synthetic signal data to cross correlate before moving on with real data but the xcorr function is returning an odd result.
I have added a delay onto either the start (delay =100) or end of the respective data sets which are the same size (2101 x 1 double) and put them through xcorr which has returned an array (4201 x 1 double).
The result has NaNs between rows 101 and 2205 and then a ring down effect after that start at an order of x10^5. I have now attached pictures of the result
Can anyone please offer some suggestions on how to correct what I am attempting to do? I am expecting to be able to plot the result and see a spike at the delay that I have set.
Thanks
EDIT:
Short example code
X = [-4.99 -0.298 4.95 12.06 15.76 18.86 19.00 17.82 14.35 11.77 6.71 0.80 -5.07 -11.79 -15.34 -18.60 -18.56 -19.31 -14.37 -11.51 -5.04];
Y = [14.13 18.48 7.53 -3.41 -8.41 -13.40 -15.37 -17.34 -16.83 -16.33 -12.21 -8.09 -8.80 -9.52 3.90 17.31 17.52 17.72 17.73 17.75 16.90];
N = length(X);
delay = 2;
% set up two new arrays which will have random noise at ends
Xx = zeros(N+delay,1);
Yx = zeros(N+delay,1);
for i=1:N+delay
if i<=delay
Xx(i) = rand;
elseif i>delay
Xx(i) = X(i-delay);
end
end
for i=1:N+delay
if i<=N
Yx(i) = Y(i);
elseif i>N
Yx(i) = rand;
end
end
C = xcorr(Xx,Yx);
I am trying to create a signal and then build a discrete-time signal by sampling the CT signal I create first. Until the last for-loop, things work out fine but I need to take N samples seperated by T. Without an if statement, I am getting an index out-of-bounds error and I had to limit sampling within the duration of the signal. For some reason, my code goes into if statement once and no more, and for debugging, I am printing out the values both in if and out of if. Although the logical operation should be true for more than one iteration(printing statements will show the values), it just does not print the statements inside the if-statement. What's wrong here?
function x = myA2D(b,w,p,T,N)
%MYA2D description: Takes in parameters to construct the CT-sampled DT signal
%b,w,p are Mx1 vectors and it returns Nx1 vector.
timeSpace = 0:0.001:3*pi;
xConstT = zeros(size(timeSpace));
%Construct Xc(t) signal
for k = 1:size(b,1)
temp = b(k) .* cos(w(k).*timeSpace + p(k));
xConstT = xConstT + temp;
end
plot(xConstT);
%Sampling CT-Signal to build DT-signal
disp(strcat('xConstT size',int2str(size(xConstT))));**strong text**
x = zeros(N,1);
sizeConstT = size(xConstT);
for i = 0:N-1
index = i .* T .* 1000 + 1;
disp(strcat('indexoo=',int2str(index)));
disp(strcat('xConstSizeeee',int2str(sizeConstT)));
if index <= sizeConstT
disp(strcat('idx=',int2str(index)));
disp(strcat('xSize',int2str(sizeConstT)));
%x(i+1,1) = xConstT(index);
end
end
end
sizeConstT = size(xConstT); creates an 1x2 array so you compare a float to an array, and your code enters the if loop only if comparison to each element of the array is successful. This example illustrates the issue:
if 1 <= [1 12]; disp('one'); end % <- prints 'one'
if 2 <= [1 12]; disp('two'); end % <- prints nothing
Your code will work with sizeConstT = length(xConstT);
I have written a recursive function, however, it takes a lot of time. Hence I vectorized it, but it does not yield the same result as the recursive function. This is my non-vectorized code:
function visited = procedure_explore( u, adj_mat, visited )
visited(u) = 1;
neighbours = find(adj_mat(u,:));
for ii = 1:length(neighbours)
if (visited(neighbours(ii)) == 0)
visited = procedure_explore( neighbours(ii), adj_mat, visited );
end
end
end
This is my vectorized code:
function visited = procedure_explore_vec( u, adj_mat, visited )
visited(u) = 1;
neighbours = find(adj_mat(u,:));
len_neighbours=length(neighbours);
visited_neighbours_zero=visited(neighbours(1:len_neighbours)) == 0;
if(~isempty(visited_neighbours_zero))
visited = procedure_explore_vec( neighbours(visited_neighbours_zero), adj_mat, visited );
end
end
This is the test code
function main
adj_mat=[0 0 0 0;
1 0 1 1;
1 0 0 0;
1 0 0 1];
u=2;
visited=zeros(size(adj_mat,1));
tic
visited = procedure_explore( u, adj_mat, visited )
toc
visited=zeros(size(adj_mat,1));
tic
visited = procedure_explore_vec( u, adj_mat, visited )
toc
end
This is the algorithm I'm trying to implement:
If vectorization is impossible, a mex solution would also be good.
Update benchmark: This benchmark is based on MATLAB 2017a. It shows that the original code is faster than other methods
Speed up between original and logical methods is 0.39672
Speed up between original and nearest methods is 0.0042583
Full code
function main_recersive
adj_mat=[0 0 0 0;
1 0 1 1;
1 0 0 0;
1 0 0 1];
u=2;
visited=zeros(size(adj_mat,1));
f_original=#()(procedure_explore( u, adj_mat, visited ));
t_original=timeit(f_original);
f_logical=#()(procedure_explore_logical( u, adj_mat ));
t_logical=timeit(f_logical);
f_nearest=#()(procedure_explore_nearest( u, adj_mat,visited ));
t_nearest=timeit(f_nearest);
disp(['Speed up between original and logical methods is ',num2str(t_original/t_logical)])
disp(['Speed up between original and nearest methods is ',num2str(t_original/t_nearest)])
end
function visited = procedure_explore( u, adj_mat, visited )
visited(u) = 1;
neighbours = find(adj_mat(u,:));
for ii = 1:length(neighbours)
if (visited(neighbours(ii)) == 0)
visited = procedure_explore( neighbours(ii), adj_mat, visited );
end
end
end
function visited = procedure_explore_nearest( u, adj_mat, visited )
% add u since your function also includes it.
nodeIDs = [nearest(digraph(adj_mat),u,inf) ; u];
% transform to output format of your function
visited = zeros(size(adj_mat,1));
visited(nodeIDs) = 1;
end
function visited = procedure_explore_logical( u, adj_mat )
visited = false(1, size(adj_mat, 1));
visited(u) = true;
new_visited = visited;
while any(new_visited)
visited = any([visited; new_visited], 1);
new_visited = any(adj_mat(new_visited, :), 1);
new_visited = and(new_visited, ~visited);
end
end
Here's a fun little function that does a non-recursive breadth-first search on the graph.
function visited = procedure_explore_logical( u, adj_mat )
visited = false(1, size(adj_mat, 1));
visited(u) = true;
new_visited = visited;
while any(new_visited)
visited = any([visited; new_visited], 1);
new_visited = any(adj_mat(new_visited, :), 1);
new_visited = and(new_visited, ~visited);
end
end
In Octave, this runs about 50 times faster than your recursive version on a 100x100 adjacency matrix. You'll have to benchmark it on MATLAB to see what you get.
You can think of your adjacency matrix as a list of paths of length exactly one. You can generate paths of other lengths n by taking it to the n-th power up to the rank of your matrix. (adj_mat^0 is the identity matrix)
In a graph with n nodes, the longest path cannot be longer than n-1, therefore you can sum all the powers together for a reachability analysis:
adj_mat + adj_mat^2 + adj_mat^3
ans =
0 0 0 0
4 0 1 3
1 0 0 0
3 0 0 3
This is the number of (different) ways that you can use to go from one node to another. For simple reachablitity, check whether this value is greater than zero:
visited(v) = ans(v, :) > 0;
Depending on your definition, you may have to change columns and rows in the result (i.e. take ans(:, v)).
For performance, you can use the lower powers to make higher ones. For example something like A + A^2 + A^3 + A^4 + A^5 would be efficiently calculated:
A2 = A^2;
A3 = A2*A
A4 = A2^2;
A5 = A4*A;
allWalks= A + A2 + A3 + A4 + A5;
Note: If you want to include the original node as being reachable from itself, you should include the identity matrix in the sum.
This minimizes the number of matrix multiplications, also MATLAB will likely execute a matrix square faster than a regular multiplication.
In my experience, matrix multiplication is relatively fast in MATLAB and this will yield the result (reachability) vector for all the nodes in the graph at once. If you are only interested in a small subset of a large graph, this is probably not the best solution.
See also this answer: https://stackoverflow.com/a/7276595/1974021
I don't think you can properly vectorise your function: Your original function never reaches the same node multiple times. By vectorising it you would pass all directly connected nodes at the same time to the next function. Therefore it then would be possible that in the following instances the same node gets reached multiple times. E.g. in your example node 1 would be reached 3 times. So while you would no longer have a loop, the function might, depending on your network, be called more times recursively which would increase the computational time.
That being said, it is not generally impossible to find all reachable nodes without loops or recursive calls. For example you could check all (valid or invalid) paths. But that would work very different from your function and, depending on the number of nodes, might result in a performance loss due to the staggering amount of paths to be checked. Your current function isn't too bad and will scale well with large networks.
A bit offtopic, but since Matlab 2016a you can use nearest() to find all reachable nodes (without the starting node). It invokes a breadth-first algorithm in contrast to your depth-first algorithm:
% add u since your function also includes it.
nodeIDs = [nearest(digraph(adj_mat),u,inf) ; u];
% transform to output format of your function
visited = zeros(size(adj_mat,1));
visited(nodeIDs) = 1;
If this is for a students project, you could argue that while your function works you used the built-in function for performance reasons.
The problem with the recursive function is related to visited(u) = 1;. That is because MATLAB uses copy-on-write technique to pass/assign variables. If you don't change visited in the body of function no copy of it is made but when it is modified a copy of it is created and modification is applied on a copy of it. To prevent that you can use a handle object to be passed by reference to the function.
Define a handle class (save it to visited_class.m):
classdef visited_class < handle
properties
visited
end
methods
function obj = visited_class(adj_mat)
obj.visited = zeros(1, size(adj_mat,1));
end
end
end
The recursive function:
function procedure_explore_handle( u, adj_mat,visited_handle )
visited_handle.visited(u) = 1;
neighbours = find(adj_mat(u,:));
for n = neighbours
if (visited_handle.visited(n) == 0)
procedure_explore_handle( n, adj_mat , visited_handle );
end
end
end
Initialize variables:
adj_mat=[0 0 0 0;
1 0 1 1;
1 0 0 0;
1 0 0 1];
visited_handle = visited_class(adj_mat);
u = 2;
Call it as :
procedure_explore_handle( u, adj_mat,visited_handle );
The result is saved into visited_handle:
disp(visited_handle.visited)
If you want to go from one point in the graph to another, the most efficient way to find it in terms of resources is Dijkstra's algorithm. The Floyd-Warshall algorithm computes all the distances between all points and can be parallellised (by starting from multiple points).
Why the need to vectorise (or use mex programming)? If you just want to make the most use of Matlab's fast matrix multiplication routines then using products of A should get you there quickly:
adj_mat2=adj_mat^2; % allowed to use 2 steps
while (adj_mat2 ~= adj_mat) % check if new points were reached
adj_mat=adj_mat2; % current set of reachable points
adj_mat2=(adj_mat^2)>0; % allowed all steps again: power method
end
This answer just gives an explicit, vectorized implementation of the suggestion from DasKrümelmonster's answer, which I think is faster than the code in the question (at least if the dimensions of the matrix are not too big). It uses the polyvalm function to evaluate the sum of powers of the adjacency matrix.
function visited = procedure_explore_vec(u, adj_mat)
connectivity_matrix = polyvalm(ones(size(adj_mat,1),1),adj_mat)>0;
visited = connectivity_matrix(u,:);
end
I have a function of this form in MATLAB,
C=S*e^(L*t)*inv(S)*C_0
where my
S=[-2 -3;3 -2]
L=[0.5 0; 0 1.5]
C_0=[1; 1]
I need to plot this function with respect to time. My output C is a 2-by-1 matrix.
What I have done is computed e^L separately using b=expm(L) and then I inserted mpower(b,t) into the function. So my resulting function in the script looks like
b=expm(L);
C=S*mpower(b,t)*inv(S)*C_0;
Now, how should I go about plotting this w.r.t time. I tried defining the time vector and then using it, but quite obviously I get the error message which says matrix dimensions do not agree. Can someone give me a suggestion?
You can probably do this in a vectorised manner but if you're not worried about speed or succinct code, why not just write a for loop?
ts = 1 : 100;
Cs = zeros(2, length(ts) );
S = [-2 -3;3 -2];
L = [0.5 0; 0 1.5];
C_0 = [1; 1];
for ii = 1 : length(ts)
b = expm(L);
Cs(:,ii) = S*mpower(b,ts(ii))*inv(S)*C_0;
end
ts contains the time values, Cs contains the values of C at each time.