Convert for loop into vector expression - matlab

I'm new to MATLAB and learning to use vector expressions instead of verbose for loops. I have a snippet and I was wondering whether it could even be written in a concise vector and if so how would I modify it.
for v = I
X(i, v) = X(i, v) + length(I(I == v));
end
X is 1500x200
I is 3763x1
i can be thought of as a constant
What I'm doing here is this. I contains column indexes of X and I want to increment those locations by the number of times that particular index appeared in I. So after this for loop is done the ith row of X will contain a histogram.
Any other ideas or suggestions to improve my MATLAB coding would also be appreciated.

Here's a couple of ways:
I = randi(10, [50,1]);
X = zeros (1, 10);
for Col = 1 : size (X, 2)
X(1, Col) = sum (I == Col);
end
% X = 7 7 3 3 7 4 5 8 1 5
X = zeros (1, 10);
for Col = I.' % the transpose operation is needed to convert to horizontal!
X(1, Col) += 1;
end
% X = 7 7 3 3 7 4 5 8 1 5
X = zeros (1, 10);
X = accumarray (I, ones (size (I)), size (X))
% X = 7 7 3 3 7 4 5 8 1 5

Related

Sudoku solver recursive backtracking not terminating

I wrote a MATLAB program that solves a 9 x 9 Sudoku puzzle using the recursive backtracking solution, but the recursion does not seem to terminate. When I pause the debugger and look at the board, I find that that my board already contains the correct solutions. In my approach, I work through the board elements column by column, starting from element 1 in (1, 1) and ending at element 81 at (9, 9). checkSudoku checks if the number is a valid placement by looking at the row, col and 3x3 subgrid. h is where the recursion occurs. Could anyone offer advice as to where my code went wrong?
function result = h(board, num)
if num >= 82
result = board;
else
if isnan(board(num))
flag = false;
c = ceil(num / 9);
r = num - ((c - 1) * 9);
n = 1;
while (n <= 9) & (~flag)
if checkSudoku(board, r, c, n)
board(num) = n;
product = h(board, num + 1);
if ~isnan(product)
flag = true;
board(num) = n;
else
board(num) = NaN;
n = n + 1;
end
else
n = n + 1;
end
end
if ~flag
result = NaN;
else
result = h(board, num + 1);
end
else
result = h(board, num + 1);
end
end
end
function safe = checkSudoku(board, row, col, num)
r = row;
c = col;
subrow = board(r, :);
subcol = board(:, col);
subBoard = zeros(3, 3);
if any([1 2 3] == r)
if any([1 2 3] == c)
subBoard = board(1:3, 1:3);
elseif any([4 5 6] == c)
subBoard = board(1:3, 4:6);
else
subBoard = board(1:3, 7:9);
end
elseif any([4 5 6] == r)
if any([1 2 3] == c)
subBoard = board(4:6, 1:3);
elseif any([4 5 6] == c)
subBoard = board(4:6, 4:6);
else
subBoard = board(4:6, 7:9);
end
else
if any([1 2 3] == c)
subBoard = board(7:9, 1:3);
elseif any([4 5 6] == c)
subBoard = board(7:9, 4:6);
else
subBoard = board(7:9, 7:9);
end
end
if any(subrow == num)
safe = false;
elseif any(subcol == num)
safe = false;
elseif any(any(subBoard == num))
safe = false;
else
safe = true;
end
end
function solvedBoard = solveSudoku(board)
solvedBoard = h(board, 1);
end
I took the problem and the MATLAB file from MITOpenCourseWare, homework 3 optional question 3. The file and photo can be found here.
Recursive functions can be tricky to abstract even in the simple cases. Your case have a extra layer of complexity as on top of having to calculate things based on previous iterations, the algorithm should also be able to backtrack a certain number of iterations, before continuing the way forward.
I made a working example, but it is not the only way to achieve the result. The way I propose make use of two flags to help the recursive function knows in which direction it is going. You could do without flags but it would involve doing more checks during the function to assess the state of the board. Since the capability is there to use flags I made use of it to simplify.
I would strongly recommend you read the documentation on return as it is a useful tool for these types of functions.
Now on to the answer:
The starting board:
Firstly, for everybody's benefit, I present the starting unsolved board. It is a 9x9 matrix containing the initial numbers and NaN everywhere else.
unsolvedBoard = [
5 3 NaN NaN 7 NaN NaN NaN NaN
6 NaN NaN 1 9 5 NaN NaN NaN
NaN 9 8 NaN NaN NaN NaN 6 NaN
8 NaN NaN NaN 6 NaN NaN NaN 3
4 NaN NaN 8 NaN 3 NaN NaN 1
7 NaN NaN NaN 2 NaN NaN NaN 6
NaN 6 NaN NaN NaN NaN 2 8 NaN
NaN NaN NaN 4 1 9 NaN NaN 5
NaN NaN NaN NaN 8 NaN NaN 7 9 ] ;
The starting conditions:
Your algorithm was iterating blindly over all the 99 possible boxes of the grid. The problem statement recommended you to identify the empty indices in the grid (to be placed in a emptyInd variable, and only iterate through these empty indices thanks to a variable ind.
To incorporate that I modified the start of the main solver:
function solvedBoard = solveSudoku(board)
emptyInd = find(isnan(board)) ; % find the empty indices in the grid
% this will solve the board recursively
solvedBoard = solverec( board, emptyInd, 1 );
end
Now emptyInd contains only 51 indices to be found. We'll only iterate on these and not on the 99 boxes of the grid.
The possible numbers for a given box:
Your function checkSudoku(board, row, col, num) was working perfectly fine, but can be simplified. You were already converting row and column indices to linear indices in your h function, you can reuse the same type of calculations in this function to know the indices of the subrow/subcol/subBoard.
Also note that you can merge the if conditions with the logical or to check all the conditions at once.
The function can become:
function safe = checkSudoku(board, row, col, num)
subrow = board(row, :);
subcol = board(:, col);
subSquareRow = (1:3) + 3*(ceil(row/3)-1) ;
subSquareCol = (1:3) + 3*(ceil(col/3)-1) ;
subBoard = board( subSquareRow , subSquareCol );
subBoard = subBoard(:) ; % Reshape into column vector (easier comparison)
% This whole block can be replaced with the line described below
if any(subrow == num) || any(subcol == num) || any(any(subBoard == num))
safe = false;
else
safe = true;
end
% Note that since we are dealing with boolean, the "IF" check above could
% be avoided and simply written as :
% safe = ~( any(subrow == num) || any(subcol == num) || any(any(subBoard == num)) ) ;
end
Now this function is later used in the recursive loop to check if a number from 1 to 9 is valid in a given position. You used a while loop to run from 1 to 9. I find that wasteful to check nine numbers when we could know from the start the few possible candidates for a given box. So I wrote a function which return a list of the only possible valid number for a box. If it returns only 3 possible numbers, I will only have to iterate through these 3 numbers, instead of doing it blindly over 9 ot them.
function candidates = getCandidates(board, row, col)
subrow = board(row, :);
subcol = board(:, col);
subSquareRow = (1:3) + 3*(ceil(row/3)-1) ;
subSquareCol = (1:3) + 3*(ceil(col/3)-1) ;
subBoard = board( subSquareRow , subSquareCol );
subBoard = subBoard(:) ; % Reshape into column vector (easier comparison)
% Get the difference of each array compared to a reference line
refval = 1:9 ;
cdrow = setdiff(refval,subrow) ;
cdcol = setdiff(refval,subcol) ;
cdsqr = setdiff(refval,subBoard) ;
% intersection of the three arrays
candidates = intersect( intersect(cdrow,cdcol) , cdsqr ) ;
end
You can read up on setdiff and on intersect to understand how it works.
Now the recursive solver:
This function is doing the job of your h() function. You were having 2 main problems in your implementation:
Too many conditional branches: the program flow had too many if
branches, and some paths were actually never used. Even when it works
it is confusing, but often confusion also introduce errors.
No robust condition to check when the board was fully solved: you had a check,
but it wasn't capturing the board completion (in part due to the problem above).
What was hapening is when your board was fully solved, the algorithm has no way to detect that and work back through the iterative function call with the final result in hand. You algorithm was finding the solution, but with the lack of an exit door for this case (fully solved), it was defaulting to the other branches and eventually consistently reverting the last few iterations, even though they were correct.
The following implementation seem to work ok for our test case and a couple of other. You can try it on other cases if you want, just be aware that the grid must be solvable. I did not put any check or instruction on what to do if the grid is not solvable so I don't know what will happen if you run it on such a grid.
Code for solverec.m:
function [res, solved, noSolutionFound] = solverec(board,emptyInd,ind,solved)
%% initialise the return flag for first function call
if nargin < 4 ; solved = false ; end
noSolutionFound = false ; % initialise second flag
% check if we are done with all the EmptyInd
if ind>numel(emptyInd) ;
solved = true ;
end
%% Return quickly if the board is already solved
if solved
res = board ;
return ;
end
%% If we are here, we still have to find new emptyInd
% prepare useful indices (row, column & linear index)
num = emptyInd(ind) ;
col = ceil(num / 9);
row = num - ((col - 1) * 9);
% get possible candidates for this box
cd = getCandidates(board, row, col) ;
ncd = numel(cd) ; % number of candidates
if ncd == 0
% no candidate for this box => back track
noSolutionFound = true ;
else
% Try the possible candidates one by one
for k=1:ncd ;
board(num) = cd(k) ; % try one candidate
% move on to next emptyInd
[res, solved, noSolutionFound] = solverec(board,emptyInd,ind+1,solved) ;
% bail out if solved
if solved ; return ; end
% otherwise, reset this emptyInd before trying next candidate
if noSolutionFound
board(num) = NaN ;
end
end
end
if noSolutionFound
% We have exhausted all possible candidates for this emptyInd
% We have to back track further
board(num) = NaN ;
res = board ;
return % this one is actually optional, the function will "return"
% anyway at the end of the "if" block.
end
end
Testing:
>> solvedBoard = solveSudoku(unsolvedBoard)
solvedBoard =
5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9
I'll let you write the optional displaySudoku(board) function as an exercise ;)

Matrix periodic boundary conditions Matlab

I need some help, i have a matrix rapresenting points on a grid and when given a element i would like to find the indices of its nearest neighbors keeping in mind that i have periodic boundary conditions, so that if i have the element A(1,1) its nearest neighbors are
A(1,N)
A(2,1)
A(1,2)
A(N, 1)
Where A is my matrix and N is the dimension, and i need a code which will find the indices of n.n of a given element.
Thanks in advance.
Here's my interpretation of your problem:
Given some periodic matrix A:
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
and some element x (example 1), then find the (i,j) indices of the 4 neighbours of x. In this case, the indices (3, 4), (4,3), (4, 1), (1, 4) correspond to 12, 15, 4, 13.
Since I don't know your use case, I don't know in what format the indices are most convenient for you. But as an example, we can write a function neighbors which returns a struct with the 4 indices of the element x.
function out = neighbors(A, x)
[m, n] = size(A);
[i, j] = find(A == x);
mod2 = #(x) mod(x-1, [m, n])+1;
out.down = mod2([i+1, j ]);
out.up = mod2([i-1, j ]);
out.right = mod2([i , j+1]);
out.left = mod2([i , j-1]);
end
We can then run the function as follows.
A = magic(4);
out = neighbors(A, 1);
A(out.left(1), out.left(2)); % this returns 15
A(out.right(1), out.right(2)); % this returns 4
A(out.up(1), out.up(2)); % this returns 12
A(out.down(1), out.down(2)); % this returns 13

Multiply matrix columns with decreasing elements starting by the last column

I have a matrix with following shape:
A = [1 2 3;
4 5 6;
7 8 9]
Now I want starting with the last column to multiply the column with a number and then decrease the number and move to the next column.
So if we start with the number 1 and use for step 0.2 to modify all columns:
Anew = [1*0.6 2*0.8 3*1;
4*0.6 5*0.8 6*1;
7*0.6 8*0.8 9*1]
Or for second example we start with 0.9 with 0.1 as step and modify 3 columns:
B = [1 2 3 4;
5 6 7 8;
9 10 11 12;
13 14 15 16]
And to get:
Bnew = [1 2*0.7 3*0.8 4*0.9;
5 6*0.7 7*0.8 8*0.9;
9 10*0.7 11*0.8 12*0.9;
13 14*0.7 15*0.8 16*0.9]
The matrices might vary in their amount of columns, and I would like to set starting number, ending number, step number and the amount of columns I want to modify.
What you are describing can be achieved with broadcasted element-wise multiplication in matlab R2016b and beyond.
Let's say your inputs are the matrix A, start value start, step size step, and number n. You can start by constructing the factors you want to multiply by. I am going to assume that when n > size(A, 2), you want to just use the first n steps rather than error out:
k = size(A, 2);
n = min(n, k);
factors = ones(1, k);
factors(1 + k - n:end) = linspace(start - (n - 1) * step, start, n);
Now you can just multiply your matrix:
result = A .* factors;
This solution has the advantage of being extremely simple and fully vectorized.
If you have an older version of MATLAB, do the following instead:
result = A .* repmat(factors, size(A, 1), 1);
Or use Tony's trick:
result = A .* factors(ones(3, 1), :)
I just found the solution:
count = 0;
A = randi([-10,10],4,4);
Anew = [];
for i=0.9:-0.1:0
number_columns = 3;
if count == number_columns
rest = existing_columns - count;
for i=rest:-1:1
Anew = [(A(:,i)) Anew];
end
break
end
existing_columns = size(A,1);
Anew = [(A(:,existing_columns-count)*i) Anew];
count = count + 1;
end

average number of different values in a column

I had a question in Matlab. It is so, I try to take average of the different number of values ​​in a column. For example, if we have the column below,
X = [1 1 2 3 4 3 8 2 1 3 5 6 7 7 5]
first I want to start by taking the average of 5 values ​​and plot them. In the case above, I should receive three averages that I could plot. Then take 10 values ​​at a time and so on.
I wonder if you have to write custom code to fix it.
The fastest way is probably to rearrange your initial vector X into some matrix, with each column storing the required values to average:
A = reshape(X, N, []);
where N is the desired number of rows in the new matrix, and the empty brackets ([]) tell MATLAB to calculate the number of columns automatically. Then you can average each column using mean:
X_avg = mean(A);
Vector X_avg stores the result. This can be done in one line like so:
X_avg = mean(reshape(X, N, []));
Note that the number of elements in X has to be divisible by N, otherwise you'll have to either pad it first (e.g with zeroes), or handle the "leftover" tail elements separately:
tail = mod(numel(X), N);
X_avg = mean(reshape(X(1:numel(X) - tail), N, [])); %// Compute average values
X_avg(end + 1) = mean(X(end - tail + 1:end)); %// Handle leftover elements
Later on you can put this code in a loop, computing and plotting the average values for a different value of N in each iteration.
Example #1
X = [1 1 2 3 4 3 8 2 1 3 5 6 7 7 5];
N = 5;
tail = mod(numel(X), N);
X_avg = mean(reshape(X(1:numel(X) - tail), N, []))
X_avg(end + 1) = mean(X(end - tail + 1:end))
The result is:
X_avg =
2.2000 3.4000 6.0000
Example #2
Here's another example (this time the length of X is not divisible by N):
X = [1 1 2 3 4 3 8 2 1 3 5 6 7 7 5];
N = 10;
tail = mod(numel(X), N);
X_avg = mean(reshape(X(1:numel(X) - tail), N, []))
X_avg(end + 1) = mean(X(end - tail + 1:end))
The result is:
X_avg =
2.8000 6.0000
This should do the trick:
For a selected N (the number of values you want to take the average of):
N = 5;
mean_vals = arrayfun(#(n) mean(X(n-1+(1:N))),1:N:length(X))
Note: This does not check if Index exceeds matrix dimensions.
If you want to skip the last numbers, this should work:
mean_vals = arrayfun(#(n) mean(X(n-1+(1:N))),1:N:(length(X)-mod(length(X),N)));
To add the remaining values:
if mod(length(X),N) ~= 0
mean_vals(end+1) = mean(X(numel(X)+1-mod(length(X),N):end))
end
UPDATE: This is a modification of Eitan's first answer (before it was edited). It uses nanmean(), which takes the mean of all values that are not NaN. So, instead of filling the remaining rows with zeros, fill them with NaN, and just take the mean.
X = [X(:); NaN(mod(N - numel(X), N), 1)];
X_avg = nanmean(reshape(X, N, []));
It would be helpful if you posted some code and point out exactly what is not working.
As a first pointer. If
X = [1 1 2 3 4 3 8 2 1 3 5 6 7 7 5]
the three means in blocks of 5 you are interested in are
mean(X(1:5))
mean(X(6:10))
mean(X(11:15))
You will have to come up with a for loop or maybe some other way to iterate through the indices.
I think you want something like this (I didn't use Matlab in a while, I hope the syntax is right):
X = [1 1 2 3 4 3 8 2 1 3 5 6 7 7 5],
currentAmount=5,
block=0,
while(numel(X)<=currentAmount)
while(numel(X)<=currentAmount+block*currentAmount)
mean(X(block*currentAmount+1:block*currentAmount+currentAmount));
block =block+1;
end;
currentAmount = currentAmount+5;
block=0;
end
This code will first loop through all elements calculating means of 5 elements at a time. Then, it will expand to 10 elements. Then to 15, and so on, until the number of elements from which you want to make the mean is bigger than the number of elements in the column.
If you are looking to average K random samples in your N-dimensional vector, then you could use:
N = length(X);
K = 20; % or 10, or 30, or any integer less than or equal to N
indices = randperm(N, K); % gives you K random indices from the range 1:N
result = mean(X(indices)); % averages the values of X at the K random
% indices from above
A slightly more compact form would be:
K = 20;
result = mean(X(randperm(length(X), K)));
If you are just looking to take every K consecutive samples from the list and average them then I am sure one of the previous answers will give you what you want.
If you need to do this operation a lot, it might be worth writing your own function for it. I would recommend using #EitanT's basic idea: pad the data, reshape, take mean of each column. However, rather than including the zero-padded numbers at the end, I recommend taking the average of the "straggling" data points separately:
function m = meanOfN(x, N)
% function m = meanOfN(x, N)
% create groups of N elements of vector x
% and return their mean
% if numel(x) is not a multiple of N, the last value returned
% will be for fewer than N elements
Nf = N * floor( numel( x ) / N ); % largest multiple of N <= length of x
xr = reshape( x( 1:Nf ), N, []);
m = mean(xr);
if Nf < N
m = [m mean( x( Nf + 1:end ) )];
end
This function will return exactly what you were asking for: in the case of a 15 element vector with N=5, it returns 3 values. When the size of the input vector is not a multiple of N, the last value returned will be the "mean of what is left".
Often when you need to take the mean of a set of numbers, it is the "running average" that is of interest. So rather than getting [mean(x(1:5)) mean(x(6:10)) mean(11:15))], you might want
m(1) = mean(x(1:N));
m(2) = mean(x(2:N+1));
m(3) = mean(x(3:N+2));
...etc
That could be achieved using a simple convolution of your data with a vector of ones; for completeness, here is a possible way of coding that:
function m = meansOfN(x, n)
% function m = meansOfN(x, n)
% taking the running mean of the values in x
% over n samples. Returns a row vector of size (sizeof(x) - n + 1)
% if numel(x) < n, this returns an empty matrix
mv = ones(N,1) / N; % vector of ones, normalized
m = convn(x(:), mv, 'valid'); % perform 1D convolution
With these two functions in your path (save them in a file called meanOfN.m and meansOfN.m respectively), you can do anything you want. In any program you will be able to write
myMeans = meanOfN(1:30, 5);
myMeans2 = meansOfN(1:30, 6);
etc. Matlab will find the function, perform the calculation, return the result. Writing your custom functions for specific operations like this can be very helpful - not only does it keep your code clean, but you only have to test the function once...

matlab: simple matrix filtering - group size

I have a huuuge matrix storing information about X and Y coordinates of multiple particle trajectories , which in simplified version looks like that:
col 1- track number; col 2- frame number; col 2- coordinate X; col 3- coordinate Y
for example:
A =
1 1 5.14832 3.36128
1 2 5.02768 3.60944
1 3 4.85856 3.81616
1 4 5.17424 4.08384
2 1 2.02928 18.47536
2 2 2.064 18.5464
3 1 8.19648 5.31056
3 2 8.04848 5.33568
3 3 7.82016 5.29088
3 4 7.80464 5.31632
3 5 7.68256 5.4624
3 6 7.62592 5.572
Now I want to filter out trajectories shorter than lets say 4 and keep remaining stuff like (note renumbering of trajectories):
B =
1 1 5.14832 3.36128
1 2 5.02768 3.60944
1 3 4.85856 3.81616
1 4 5.17424 4.08384
2 1 8.19648 5.31056
2 2 8.04848 5.33568
2 3 7.82016 5.29088
2 4 7.80464 5.31632
2 5 7.68256 5.4624
2 6 7.62592 5.572
How to do it efficiently? I can think about some ideas using for loop and vertcat, but its the slowest solution ever :/
Thanks!
This will filter out those trajectories of length less than 4:
[v, u1, w] = unique(A(:, 1), 'last');
[~, u2, ~] = unique(A(:, 1), 'first');
keys = v(find(u1 - u2 >= 3));
B = A(ismember(A(:, 1), keys), :);
This will re-number them:
[~, ~, B(:, 1)] = unique(B(:, 1));
Here is a slightly different solution than that of #Ansari:
t = 1:max(A(:,1)); %# possible track numbers
tt = t( histc(A(:,1),t) >= 4 ); %# tracks with >= 4 frames
B = A(ismember(A(:,1),tt),:); %# filter rows
[~,~,B(:,1)] = unique(B(:,1)); %# renumber track numbers
Another way to compute the indices variable tt in my code above:
tt = find( accumarray(A(:,1), 1, [], #(x)numel(x)>=4) );