Shortest Route in a Matrix - matlab

I want to find the shortest path in this for an NXN MATRIX like the 3X3 matrix below. starting at any row of column 1 and ends at any row of column 3. The shortest path in the matrix A below is 1, 3, 2, 4.
A = [1 3 9;
4 2 4;
5 4 9];

The standard way is to first represent your problem as a graph. In your case, if you treat each cell in your matrix as a vertex, there is an edge from that vertex to the cell on the right, the cell above, and the cell below (any one of which may not exist because they fall off the edge of the matrix). Backtracking to a previous column cannot contribute to a shortest path, so we don't include those edges. If you did include them, the answer would come out the same, it just might take a fraction longer.
Using index numbering, then, we have the following edges and weights:
i j s
[1,2]=4
[1,4]=3
[2,1]=1
[2,3]=5
[2,5]=2
[3,2]=4
[3,6]=4
[4,5]=2
[4,7]=9
[5,4]=3
[5,6]=4
[5,8]=4
[6,5]=2
[6,9]=9
[7,8]=4
[8,7]=9
[8,9]=9
[9,8]=4
(The labels i,j and s are used below.) But this doesn't account for the initial cost of moving to the first column, so we add a new node that has edges to each of those nodes:
i j s
[10,1]=1
[10,2]=4
[10,3]=3
Unfortunately, I haven't found a clever way of doing this, but it's fairly straightforward and once you're finished you have the 3 column vectors you need to create a sparse matrix using:
S = sparse(i,j,s,m,n,nzmax)
where
i,j,s are column vectors as labeled from the edge/weight list above
m = n = numel(A)+1
nzmax = numel(i) = numel(j) = numel(s)
From there you would use Dijkstra's Algorithm to find the single-source shortest path starting from the new node 10. Your answer would be the node on the rightmost column (node 7, 8 or 9, in this case) with the smallest path distance.
If you have the bioinformatics toolbox, you can use shortestpath. If you don't, there are several implementations of Dijkstra's on File Exchange.

Related

Splitting Vector into Sub-vectors MATLAB

I am trying to figure out how to split a vector in matlab into subvectors.
I am solving a differential equation numerically using dde23. When You do this the length of the solution vector changes. Thus, I am finding it not so easy to use the mat2cell command that many people suggest.
All I am trying to do is split (as evenly as possible) a vector of length N into an arbitrary amount of sub-vectors whose length may vary depending on the length of the time vector. I am doing this so then I can find the maximum value of each vector on in each interval.
If I understand the question, maybe you can try to split it by using code below
dataset=[ 1 2 3 4 5 6 7 8 9 10]
splitpoint = randi[2 length(dataset)-1]
subset1 = dataset(1,1:splitpoint)
splitpoint = randi[length(subset1)+1 length(dataset)-1]
subset2 = dataset(1,length(subset1)+1:splitpoint)
After that you can choose where to finish and accept rest of it for last subset or you can define one list to hold each subset in the row of the list. So you can define while loop to handle it automatically by defining stop_criteria.

Matlab: Create a zero matrix with 1 in a particular place

For example, I can create a zeros(100). But I want the entry of row 58 and column 59 to be 1. But I need temporary variable and multiple lines to do this.
a. Let this matrix be M. How can I do this in one line? M = ....?
P.S.
b. Better still, sometimes I want two or more entries of the zero matrix be 1.
Again, how can I do this?
If I can do a. in one-line, of course I can add them up. But is there any special function to do fill zero matrix entries with 1?
First, remember that a one line expression isn't always the most effective. It could also be harder to read/understand.
One way to do this is by using a sparse matrix
The following example creates a 10x10 zero-matrix with ones at [5,2] (row 5, col 2) and [7 5]
full(sparse([5 7],[2 5],1,10,10))
Use full to convert it from a sparse matrix to a "full" one
Another (faster but maybe not as intuitive) alternative is to use accumarray
accumarray([5 2;7 5],1,[10,10])
Remember that the index values above is used directly in the expression to get on one line, the better option would be to create them separately
points = [5 2; 7 5]
or perhaps,
rowIdx = [5 7];
colIdx = [2 5];

Modifying matrix values ± a specific index value - MATLAB

I am attempting to create a model whereby there is a line - represented as a 1D matrix populated with 1's - and points on the line are generated at random. Every time a point is chosen (A), it creates a 'zone of exclusion' (based on an exponential function) such that choosing another point nearby has a much lower probability of occurring.
Two main questions:
(1) What is the best way to generate an exponential such that I can multiply the numbers surrounding the chosen point to create the zone of exclusion? I know of exppdf however i'm not sure if this allows me to create an exponential which terminates at 1, as I need the zone of exclusion to end and the probability to return to 1 eventually.
(2) How can I modify matrix values plus/minus a specific index (including that index)? I got as far as:
x(1:100) = 1; % Creates a 1D-matrix populated with 1's
p = randi([1 100],1,1);
x(p) =
But am not sure how to go about using the randomly generated number to alter values in the matrix.
Any help would be much appreciated,
Anna
Don't worry about exppdf, pick the width you want (how far away from the selected point does the probability return to 1?) and define some simple function that makes a small vector with zero in the middle and 1 at the edges. So here I'm just modifying a section of length 11 centred on p and doing nothing to the rest of x:
x(1:100)=1;
p = randi([1 100],1,1);
% following just scaled
somedist = (abs(-5:5).^2)/25;
% note - this will fail if p is at edges of data, but see below
x(p-5:p+5)=x(p-5:p+5).*somedist;
Then, instead of using randi to pick points you can use datasample which allows for giving weights. In this case your "data" is just the numbers 1:100. However, to make edges easier I'd suggest initialising with a "weight" vector which has zero padding - these sections of x will not be sampled from but stop you from having to make edge checks.
x = zeros([1 110]);
x(6:105)=1;
somedist = (abs(-5:5).^2)/25;
nsamples = 10;
for n = 1:nsamples
p = datasample(1:110,1,'Weights',x);
% if required store chosen p somewhere
x(p-5:p+5)=x(p-5:p+5).*somedist;
end
For an exponential exclusion zone you could do something like:
somedist = exp(abs(-5:5))/exp(5)-exp(0)/exp(5);
It doesn't quite return to 1 but fairly close. Here's the central region of x (ignoring the padding) after two separate runs:

Determining if any duplicate rows in two matrices in MatLab

Introduction to problem:
I'm modelling a system where i have a matrix X=([0,0,0];[0,1,0],...) where each row represent a point in 3D-space. I then choose a random row, r, and take all following rows and rotate around the point represented by r, and make a new matrix from these rows, X_rot. I now want to check whether any of the rows from X_rot is equal two any of the rows of X (i.e. two vertices on top of each other), and if that is the case refuse the rotation and try again.
Actual question:
Until now i have used the following code:
X_sim=[X;X_rot];
if numel(unique(X_sim,'rows'))==numel(X_sim);
X(r+1:N+1,:,:)=X_rot;
end
Which works, but it takes up over 50% of my running time and i were considering if anybody in here knew a more efficient way to do it, since i don't need all the information that i get from unique.
P.S. if it matters then i typically have between 100 and 1000 rows in X.
Best regards,
Morten
Additional:
My x-matrix contains N+1 rows and i have 12 different rotational operations that i can apply to the sub-matrix x_rot:
step=ceil(rand()*N);
r=ceil(rand()*12);
x_rot=x(step+1:N+1,:);
x_rot=bsxfun(#minus,x_rot,x(step,:));
x_rot=x_rot*Rot(:,:,:,r);
x_rot=bsxfun(#plus,x_rot,x(step,:));
Two possible approaches (I don't know if they are faster than using unique):
Use pdist2:
d = pdist2(X, X_rot, 'hamming'); %// 0 if rows are equal, 1 if different.
%// Any distance function will do, so try those available and choose fastest
result = any(d(:)==0);
Use bsxfun:
d = squeeze(any(bsxfun(#ne, X, permute(X_rot, [3 2 1])), 2));
result = any(d(:)==0);
result is 1 if there is a row of X equal to some row of X_rot, and 0 otherwise.
How about ismember(X_rot, X, 'rows')?

How to change elements in matrices using MATLAB

Starting wish a 7x4 binary matrix I need to change a random bit in each column to simulate error. Have been trying to no avail.
A very straightforward way to do this is to use a for loop. It might not be the most efficient approach in MATLAB, but it's probably good enough considering your data set is so small.
Iterate through each of the four columns. On each iteration, randomly chose a number from 1 to 7 to represent the row in that column that you have selected to change. Finally, flip the bit at that row/column. The following code does just this. Assume that "A" is a binary matrix with 7 rows and 4 columns
for col=1:4; %// Iterate through each column
row = ceil(7*rand()); %// Randomly chose a number from 1 to 7 to represent row
A(row,col) = ~A(row,col); %// Flip the bit at the specified row/col
end
Another possibility is to create 4 random numbers in one call, and assign in a vectorized fashion:
rowNumbers = randi(4,[1 4])
A(rowNumbers,:) = ~A(rowNumbers,:);