Vectorizing nested for loops in matlab - matlab

How do we vectorize this sort of code in matlab?
for i = 1:N
for k = 1:64
if (pixels(i,k)==1)
p(character(i),k)= p(character(i),k)+1;
end
end
end

The following should be equivalent:
[i,j] = find(pixels(i,k) == 1);
if ~isempty(i)
ind = sub2ind(size(p), character(i), j);
% or, equivalently:
% ind = character(i) + (j-1) * size(p,1);
p(ind) = p(ind) + 1;
end

Related

MATLAB find the average time using tic toc

Construct an experiment to study the performance of the Cramer rule (with two implementations
determinants) in relation to Gauss's algorithm.
In each iteration 10 random arrays A (NxN), and vectors b (Nx1) will be created.
The 10 linear systems will be solved using the Cramer rule ("cramer.m") using
of rec_det (A) and using det (A), and the Gaussian algorithm
(“GaussianElimination.m”), and the time for each technique will be the average of 10 values.
Repeat the above for N = 2 to 10 and make a graph of the average time
in relation to the dimension N.
This is my task. I dont know if the way that I calculate the average time is correct and the graphic is not displayed.
T1=0;
T2=0;
T3=0;
for N=2:10
for i=1:10
A=rand(N,N);
b=rand(N,1);
t1=[1,i];
t2=[1,i];
t3=[1,i];
tic;
crammer(A,b);
t1(i)=toc;
tic
crammer_rec(A,b);
t2(i)=toc;
tic
gaussianElimination(A,b);
t3(i)=toc;
T1=T1+t1(i);
T2=T2+t2(i);
T3=T3+t3(i);
end
avT1=T1/10;
avT2=T2/10;
avT3=T3/10;
end
plot(2:10 , avT1 , 2:10 , avT2 , 2:10 , avT3);
function x = cramer(A, b)
n = length(b);
d = det(A);
% d = rec_det(A);
x = zeros(n, 1);
for j = 1:n
x(j) = det([A(:,1:j-1) b A(:,j+1:end)]) / d;
% x(j) = rec_det([A(:,1:j-1) b A(:,j+1:end)]) / d;
end
end
function x = cramer(A, b)
n = length(b);
d = rec_det(A);
x = zeros(n, 1);
for j = 1:n
x(j) = rec_det([A(:,1:j-1) b A(:,j+1:end)]) / d;
end
end
function deta = rec_det(R)
if size(R,1)~=size(R,2)
error('Error.Matrix must be square.')
else
n = size(R,1);
if ( n == 2 )
deta=(R(1,1)*R(2,2))-(R(1,2)*R(2,1));
else
for i=1:n
deta_temp=R;
deta_temp(1,:)=[ ];
deta_temp(:,i)=[ ];
if i==1
deta=(R(1,i)*((-1)^(i+1))*rec_det(deta_temp));
else
deta=deta+(R(1,i)*((-1)^(i+1))*rec_det(deta_temp));
end
end
end
end
end
function x = gaussianElimination(A, b)
[m, n] = size(A);
if m ~= n
error('Matrix A must be square!');
end
n1 = length(b);
if n1 ~= n
error('Vector b should be equal to the number of rows and columns of A!');
end
Aug = [A b]; % build the augmented matrix
C = zeros(1, n + 1);
% elimination phase
for k = 1:n - 1
% ensure that the pivoting point is the largest in its column
[pivot, j] = max(abs(Aug(k:n, k)));
C = Aug(k, :);
Aug(k, :) = Aug(j + k - 1, :);
Aug(j + k - 1, :) = C;
if Aug(k, k) == 0
error('Matrix A is singular');
end
for i = k + 1:n
r = Aug(i, k) / Aug(k, k);
Aug(i, k:n + 1) = Aug(i, k:n + 1) - r * Aug(k, k: n + 1);
end
end
% back substitution phase
x = zeros(n, 1);
x(n) = Aug(n, n + 1) / Aug(n, n);
for k = n - 1:-1:1
x(k) = (Aug(k, n + 1) - Aug(k, k + 1:n) * x(k + 1:n)) / Aug(k, k);
end
end
I think the easiest way to do this is by creating a 9 * 3 dimensional matrix to contain all the total times, and then take the average at the end.
allTimes = zeros(9, 3);
for N=2:10
for ii=1:10
A=rand(N,N);
b=rand(N,1);
tic;
crammer(A,b);
temp = toc;
allTimes(N-1,1) = allTimes(N-1,1) + temp;
tic
crammer_rec(A,b);
temp = toc;
allTimes(N-1,2) = allTimes(N-1,2) + temp;
tic
gaussianElimination(A,b);
temp = toc;
allTimes(N-1,3) = allTimes(N-1,3) + temp;
end
end
allTimes = allTimes/10;
figure; plot(2:10, allTimes);
You can use this approach because the numbers are quite straightforward and simple. If you had a more complicated setup, the way to store the times/calculate the averages would have to be tweaked.
If you had more functions you could also use function handles and create a third inner loop, but this is a little more advanced.

How to linearize the nested parfor loop?

I have two variables i,j, where j index start depends on i index.
n = 3;
for i = 1:n
for j = i+1:n
% Feature matching
matches = getMatches(input, allDescriptors{i}, allDescriptors{j});
nf = size(matches, 2);
numMatches(i,j) = nf;
end
end
I am trying to linearize it using the below code:
n = 3;
M = n;
N = n;
parfor i = 1:M*N
% IND2SUB converts from a "linear" index into individual
% subscripts
[ii,jj] = ind2sub([M,N], i);
if (ii~=jj)
matches = getMatches(input, allDescriptors{ii}, allDescriptors{jj});
nf = size(matches, 2);
numMatches(i) = nf;
end
end
But have some entries on the lower triangular part of the square matrix.
Any help is appreciated!

Jacobi method to solve linear systems in MATLAB

How would you code this in MATLAB?
This is what I've tried, but it doesn't work quite right.
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
for k = 1:tot_it
for j = 1:n
for i = 1:n
if (j ~= i)
x(i) = -((A(i,j)/A(i,i)) * x(j) + (b(i)/A(i,i)));
else
continue;
end
end
end
end
end
j is an iterator of a sum over each i, so you need to change their order. Also the formula has a sum and in your code you're not adding anything so that's another thing to consider. The last thing I see that you're omitting is that you should save the previous state of xbecause the right side of the formula needs it. You should try something like this:
function x = my_jacobi(A,b, tot_it)
%Inputs:
%A: Matrix
%b: Vector
%tot_it: Number of iterations
%Output:
%:x The solution after tot_it iterations
n = length(A);
x = zeros(n,1);
s = 0; %Auxiliar var to store the sum.
xold = x
for k = 1:tot_it
for i = 1:n
for j = 1:n
if (j ~= i)
s = s + (A(i,j)/A(i,i)) * xold(j);
else
continue;
end
end
x(i) = -s + b(i)/A(i,i);
s = 0;
end
xold = x;
end
end

matlab, user inputs a matrix into variable

I have this code for matlab to multiply matrixes how di i make the user add the matrixes and then use the matrixes in the code?
eg [n,m] = input(user inputs matrix here)
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
You can use in the script:
A = input('input array A ');
B = input('input array B ');
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
or you can write the above as a function:
function C = matrixmultiply(A,B)
[n,m] = size(A);
[p,q] = size(B);
C = zeros(n,p);
if p~=m
error('Inner Matrix Dimensions Must Agree.')
end
for k = 1:n
for j = 1:q
temp=0;
for i = 1:p
temp = temp+(A(k,i)*B(i,j));
end
C(k,j) = temp;
end
end
end

Changing the order in for-loop

I have a matrix (with the size of A and B; suppose 100x100) and want to fill in with smaller matrix (or block) with the size of a and b (suppose 12x12).
As it is clear, the loop starts from "j" and then goes to the next row. Actually I want to use the same loop, by adding another variable to impose that it first complete the columns. Any idea that how I should define this new variable in the following loop to control the completion direction.
M = zeros(100,100);
for j = 1:12:100-12+1
for i = 1:12:100-12+1
block = rand(12,12);
M(i:i+11, j:j+11) = block;
imagesc(M); axis equal tight xy
pause(.1)
end;
end;
Why not just do
M = zeros(100,100);
for j = 1:12:100-12+1
for i = 1:12:100-12+1
block = rand(12,12);
M(i:i+11, j:j+11) = block;
imagesc(M); axis equal tight xy
pause(.1)
end;
end;
Now you will iterate over the i's first.
Incidentally, I recommend not using i and j as loop variables - they shadow the built in sqrt(-1) imaginary number...
update based on your comment, it seems you want to leave the order of i and j in the outer loop, and add "another parameter" to change the direction. The following code does all that. Is this what you are after?
M = zeros(100,100);
rowFirst = true; % set to false for "column first"
for i = 1:12:100-12+1
for j = 1:12:100-12+1
block = rand(12,12);
if rowFirst
M((0:11) + i, (0:11) + j) = block;
else
M((0:11) + j, (0:11) + i) = block;
end
imagesc(M); axis equal tight xy
pause(.1)
end
end
update 2 and now "even for non square matrix" (not tested, late at night):
M = zeros(100, 120);
rowFirst = true;
sz = size(M);
blockSize = 12;
v = 1:blockSize;
nrc = floor(sz / blockSize);
if rowFirst
nrc = reverse(nrc);
end
for ii = blockSize * (0:nrc(1)-1)
for jj = blockSize * (0:nrc(2)-1)
block = rand(blockSize*[1 1]);
if ~rowFirst
block = block';
end if
M(v + ii, v+jj) = block;
if rowFirst
imagesc(M);
else
imagesc(M');
end
axis equal tight xy
pause(0.1)
end
end
LAST TIME if you insist that the outer loop iterates over j and the inner loop over i, yet that in some instances j is the "faster moving" variable, you can do the following.
P = 120;
Q = 180;
M = zeros(P, Q); % not a square matrix
rowFirst = true; % a switch you can flip
blockSize = 15; % size of block
sz = floor(size(M)/blockSize); % number of iterations in j, i
nr = sz(1); nc = sz(2);
vv = 1:blockSize;
for jj = 0: (nc-1)
for ii = 0: (nr-1)
if(rowFirst)
kk = ii * blockSize;
ll = jj * blockSize;
else
nn = jj * nr + ii;
ll = mod(nn, nc);
kk = floor(nn / nc);
%ll = (nn - kk * nc);
fprintf(1, 'ii, jj, nn = [%d, %d, %d]: [kk, ll] = %d, %d\n', ii, jj, nn, kk, ll)
ll = ll * blockSize; kk = kk * blockSize;
% mod(nn, P);
end
M(kk+vv, ll+vv) = rand(blockSize*[1 1]);
imagesc(M);
axis tight equal xy;
pause(0.1);
end
end