Converting a matrix loop into an equivalent function - matlab

Given a recursive loop similar to the following:
A = [5,2;0,2]
B = [5;6]
x = [0;7]
for i = 1:10
x(:,i+1) = A * x(:,i) + B
end
How can this represented without a loop?
Sample output:
[ 0, 19, 140, 797, 4186, 21339, 107520, 539257, 2699606, 13504679, 67536700;
7, 20, 46, 98, 202, 410, 826, 1658, 3322, 6650, 13360]

Here is a more mathy approach by solving the general formula for your recursion
u = pinv(A-eye(2))*B;
C = arrayfun(#(n) A^n*(x+u)-u,0:10,'UniformOutput',false);
M = cat(2,C{:});
which gives
M =
Columns 1 through 9:
0 19 140 797 4186 21339 107520 539257 2699606
7 20 46 98 202 410 826 1658 3322
Columns 10 and 11:
13504679 67536700
6650 13306

I think you are looking to create a recursive function. If so, the below might work for you.
A = [5,2;0,2]
B = [5;6]
x = [0;7]
x = myRecursive(A,B,x, 10)
function [x] = myRecursive(A,B,x,n)
x(:,end+1) = A * x(:,end) + B;
if size(x,2) <= n
x = myRecursive(A,B,x,n);
end
end

Related

What is the meaning of the following matlab notation?

I want to write this matlab code in python but I do not know what LEV(1:n+1:n^2) = 0; or LEV(i,:) means. Can anyone explain me what are this notation? Thank you!
function A = ILU_p(A,p)
n = length(A);
LEV = inf(n);
LEV(find(A)) = 0;
LEV(1:n+1:n^2) = 0;
for i = 2:n
for k = 1:i-1
if LEV(i,k) > p
continue
end
A(i,k) = A(i,k) / A(k,k);
A(i,k+1:n) = A(i,k+1:n) - A(i,k) * A(k,k+1:n);
LEV(i,k+1:n) = min([LEV(i,k+1:n); LEV(i,k) + LEV(k,k+1:n) + 1]);
end
A(i,find(LEV(i,:)>p)) = 0;
end
The below sets up a vector of values to be used in an index. If n=10 then the below would yield a row vector of [1 12 23 34 45 56 67 78 89 100]
1:n+1:n^2
Since LEV is set up as an nxn matrix and the above row vector picks up the diagonal elements, i.e., LEV(1) = LEV(1,1), LEV(12) = LEV(2,2), etc.
LEV(i,:) is MATLAB's shorthand for referencing all columns in row i.

Guidance Needed For MATLAB MATRIX

I am working on a script which takes in array values and generates a matrix as shown in the code. What I want to do, based on below code, is that I want to search another matrix of given values and find the values corresponding to the cel and flr variables as defined in the program and make a new row to the matrix.
This is the current output:
C =
63.6944 51.7205 -38.2795 -39.0000 -38.0000 B value correspond to -39
107.5034 68.4665 -21.5335 -22.0000 -21.0000 B value correspond to -22
155.1031 75.2618 -14.7382 -15.0000 -14.0000 B value correspond to -15
203.8553 78.8393 -11.1607 -12.0000 -11.0000
253.0948 81.0307 -8.9693 -9.0000 -8.0000
302.5838 82.5070 -7.4930 -8.0000 -7.0000
352.2172 83.5677 -6.4323 -7.0000 -6.0000
401.9415 84.3662 -5.6338 -6.0000 -5.0000
to above I want to add another column which is searching corresponding values in given matrix say -39, -22, -15, 12, -9, -8, -7, -6 will be searched in a 2D matrix say B which is below. Now I want another column in below matrix which shows corresponding values of the matrix B in A.
B = [-39 14
-38 12
-15 10
-12 17
-9 45
-8 16]
a = 1;
for X = [50 100 150 200 250 300 350 400]
R = hypot(41.4586-2, X);
theta = atand(X/(41.4586-2));
dep = theta-90;
flr = floor(dep);
Y(row1:col1) = find(Y==flr);
dB1 = Y(row1:2);
cel = ceil(dep);
Y(row2,col2) = find(Y==cel);
dB2= Y(row2:2);
A(1,a) = R;
A(2,a) = theta;
A(3,a) = dep;
A(4,a) = flr;
A(5,a) = cel;
A(6,a) = dB1;
a = a+1;
end
C = transpose(A);
C =
63.6944 51.7205 -38.2795 -39.0000 -38.0000 14-> value of B in col 2
107.5034 68.4665 -21.5335 -22.0000 -21.0000 12
155.1031 75.2618 -14.7382 -15.0000 -14.0000 10
203.8553 78.8393 -11.1607 -12.0000 -11.0000 17
253.0948 81.0307 -8.9693 -9.0000 -8.0000 45
302.5838 82.5070 -7.4930 -8.0000 -7.0000 16
this should be the output

Loop through three arrays, apply function to elements and store the outputs in a matrix

I want to loop through different elements of 3 arrays and create a matrix as a function of their values.
My a vector ranges from 1 to 5, my b vector ranges from 1 to 5 and my x vector ranges from 2 to 10 as shown below. Then for particular values from a and b, using the equation y=a*x+b, I want the resulting y vector corresponding to the x values stored in the 1st column vector of the y matrix.
After that, changing a and b one by one, I want the results of different y to be stored in corresponding columns of the y matrix . How can I proceed to achieve that?
Here is the code I tried:
function mathstrial
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
for e1 = a
for e2 = b
for e3 = x
y = e1*x+e2;
end
end
end
disp(y)
end
I want the result to be
y =
3 4 5 6 7 ..
5 6 7 8 9 ..
7 8 9 10 11 ..
9 10 11 12 13 ..
11 12 13 14 15 ..
...
You can do this without any loops - the more "MATLAB-esque" way of doing things.
% Your a and b, to get combinations as a 5x5 grid we use meshgrid
[a,b] = meshgrid(1:5, 1:5);
% We want to make a 5x5x5 3D matrix, where the 2D layers each use a different value
% for x, and the gridded a and b we just generated. Get the layered x:
x = repmat(reshape(2:2:10, 1, 1, []), 5, 5, 1);
% Now we want the corresponding layered a and b
a = repmat(a, 1, 1, 5); b = repmat(b, 1, 1, 5);
% Now calculate the result, ensuring we use element-wise multiplication .*
y = a.*x + b;
% Reshape to be a 2D array, collapsing the 3rd dimension
y = reshape(y(:,:).', [], 5, 1);
Result as you wanted:
y =
[3, 4, 5, 6, 7
5, 6, 7, 8, 9
7, 8, 9, 10, 11
9, 10, 11, 12, 13
...
41, 42, 43, 44, 45
51, 52, 53, 54, 55]
You could easily make this more generic by using size in place of the 5s to get the appropriate sizes.
you can build up y in a single for loop
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for ct = 1:length(a)
y(:,:,ct) = (a(ct).*x)'+b;
end
with b over the second and a over the third dimension.
Or even in a single unreadable line
y=repmat((a'.*x),[1,1,length(b)])+repmat(permute(b,[1,3,2]),[length(x),length(a),1])
with a over the second, and b over the third dimension
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for i = 1:5
for j = 1:5
for k =1:5
y(i,j,k) = i*x(k)+j
end
end
end
final_y = reshape(y, [5, 25])

select a range of values from a matrix and swap them

I have a matrix and i want to select a range of elements.
for example i want to select all the elements that are lower than 182 and swap/change them.
does someone know an easy way or command to do this in matlab ?
thanx
Since you say "swap", I understand you mean a vector, not a matrix. You can do it as follows:
x = [ 1 34 66 22 200 55 301 ]; % data
[ values, ind ] = find(x<182);
x(ind) = x(ind(end:-1:1));
To simply replace them by another value such as NaN, do as follows. Note that this works also for matrices:
x = [ 1 34 66 22 200 55 301 ]; % data
x(x<182) = NaN;
Such things can usually be accomplished via logical indexing:
A = randn(1,100);
B = randn(size(A));
test = (A>1|A<0); % For example, values that are greater than 1 or less than 0
A(test) = B(test);
or another example:
A = randn(1,100);
test = (A>1|A<0);
A(test) = randn(1,nnz(test));
or another:
A = randn(1,100);
A(A>1|A<0) = NaN;
You may use loop like this:
for i = 1:length(matrix(:,1))
for j = 1:length(matrix(1,:))
if matrix(i,j) < 182
matrix(i,j) = NaN;
end
end
end

Matlab code runs too slow on three dimensional array

I'm trying to vectorize the following code:
% code before
% code before
% a lot of code before we got to the current comment
%
% houghMatrix holds some values
for i=1:n
for j=1:m
for k = 1:maximalRadius
% get the maximal threshold
if houghMatrix(i,j,k) > getMaximalThreshold(k)
lhs = [j i k];
% verify that the new circle is not listed
isCircleExist = verifyCircleExists(circles,lhs,circleCounter);
% not listed - then we put it in the circles vector
if isCircleExist == 0
circles(circleCounter,:) = [j i k];
fprintf('Circle % d: % d, % d, % d \n', circleCounter, j, i, k);
circleCounter = circleCounter + 1;
end
end
end
end
end
Using tic tac I got the below outputs :
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.111176 seconds.
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.105642 seconds.
>> x = findCircles(ii);
Circle 1: 38, 38, 35
Circle 2: 89, 51, 34
Circle 3: 72, 66, 11
Circle 4: 33, 75, 30
Circle 5: 90, 81, 31
Circle 6: 54, 96, 26
Elapsed time is 3.135818 seconds.
Meaning - average of 3.1 seconds .
I tried to vectorize the code , but the problem is that I need to use
the index i,j,k in the body of the inner for (the 3rd for) .
Any suggestions how to vectorize the code would be greatly appreciated
Thanks
EDIT :
% -- function [circleExists] = verifyCircleExists(circles,lhs,total) --
%
%
function [circleExists] = verifyCircleExists(circles,lhs,total)
MINIMUM_ALLOWED_THRESHOLD = 2;
circleExists = 0;
for index = 1:total-1
rhs = circles(index,:);
absExpr = abs(lhs - rhs);
maxValue = max( absExpr );
if maxValue <= MINIMUM_ALLOWED_THRESHOLD + 1
circleExists = 1;
break
end
end
end
Heres what I think you want to do: For each valid coordinate triplet, you want to check whether there has been a nearby triplet already, otherwise, you add it to the list. This operation can be fully vectorized if there's no possibility of "chaining", i.e. if each cluster of possible candidate voxels can only accomodate one center. In this case, you simply use:
%# create a vector of thresholds
maximalThreshold = getMaximalThreshold(1:maximalRadius);
%# make it 1-by-1-by-3
maximalThreshold = reshape(maximalThreshold,1,1,[]);
%# create a binary array the size of houghMatrix with 1's
%# wherever we have a candidate circle center
validClusters = bsxfun(#gt, houghMatrix, maximalThreshold);
%# get the centroids of all valid clusters
stats = regionprops(validClusters,'Centroid');
%# collect centroids, round to get integer pixel values
circles = round(cat(1,stats.Centroid));
Alteratively, if you want to follow your scheme of selecting valid circles, you can get the ijk indices from validClusters as follows:
[potentialCircles(:,1),potentialCircles(:,2), potentialCircles(:,3)]= ...
sub2ind(size(houghMatrix),find(validClusters));
nPotentialCircles = size(potentialCircles,1);
for iTest = 2:nPotentialCircles
absDiff = abs(bsxfun(#minus,potentialCircles(1:iTest-1,:),potentialCircles(iTest,:)));
if any(absDiff(:) <= MINIMUM_ALLOWED_THRESHOLD + 1)
%# mask the potential circle
potentialCircles(iTest,:) = NaN;
end
end
circles = potentialCircles(isfinite(potentialCircles(:,1)),:);