For loop with if and elseif statements - matlab

I have a simple problem, I'm trying to replace values in a 1x60000 array.
Here's my code, where Z is the 1x60000 array:
for i = 1:length(Z)
if Z(i) == 140
Z(i) = 1;
elseif Z(i) == 83
Z(i) = 2;
elseif Z(i) == 52
Z(i) = 3;
elseif Z(i) == 36
Z(i) = 4;
elseif Z(i) == 28
Z(i) = 5;
elseif Z(i) == 23
Z(i) = 6;
elseif Z(i) == 125
Z(i) = -1;
else
Z = Z(i);
end
end
The largest value in the array is 140. However, when I run the code I receive this error:
Index exceeds matrix dimensions.
Any help would be appreciated.

Your issue is the Z = Z(i) line, you're assigning a single value to an array then trying to index that single value next loop. If you want to leave Z(i) unchanged, simply don't use the else condition.
This whole code could be a lot shorter (and less loopy) using some logical indexing and ismember:
% Row 1 values to be replaced in Z by row 2 values
replacements = [140, 83, 52, 36, 28, 23, 125;
1, 2, 3, 4, 5, 6, -1];
% Get the indices where Z is one of the values to be changed
[~, idx] = ismember(Z, replacements(1,:));
% Use indexing to replace all the values at once
Z(idx~=0) = replacements(2, idx(idx~=0));

The line which certainly creates the error
Z = Z(i);
as you don't have any index on the left part.

Related

Nested for loop error or indexing error in MATLAB

I have created this code from scratch. I want to make a plot and/or histogram of my "Observed" and "State" (these are 2 matrices). Some problem occurs at the 200th iteration, where my State matrix just becomes all 0's, there is no data being input into the State matrix. Can anyone troubleshoot the code? My possible states are {1,2,3}.
UPDATE:
When I adjust my n value, it adjusts how much of length T it will fill. So, n=5, only runs for 1/5 of T and n=1, run for entire length of T. I need an nxT matrix at the end (5X1000). The problem lies in the way I setup my for loops.
I still cannot solve the error though.
%Initialize A,pi,T
N = 3; # of states
%A is transition prob matrix
A = [.99,.005,.005;.005,.990,.005;.005,.005,.990];
%pi is initial state vector
pi = [1/3,1/3,1/3];
%T is # of observations per simulation
T = 1000;
%n is # of simulations
n = 5;
%Allocate space for the state matrix
State = zeros(n,T);
Observe = zeros(n,T);
%Create dummy emission matrix, must be row stochastic
B = ones(n,T)./T;
%loop over # of simulations
for i=1:1:n
x = rand(1);
if x <= (1/3)
State(i,1) = 1;
elseif x > (1/3) && x <= (2/3)
State(i,1) = 2;
else
State(i,1) = 3;
end
if State(i,1) == 1
b = -1;
elseif State(i,1) == 2
b = 0;
else
b = 1;
end
Observe(i,1)= normrnd(b,1);
for k=2:1:T
%Possible state 1,2,3
State(k) = randsample(N, 1, true, A(State(k-1),:));
if State == 1
c = -1;
elseif State == 2
c = 0;
else
c = 1;
end
Observe(i,k)= normrnd(c,1);
end
end
State(k) = randsample(N, 1, true, A(State(k-1),:));
This line is missing index (i) in position 1 inside State(k-1). It should be:
State(i,k) = randsample(N, 1, true, A(State(i,k-1),:));

How can I use an if-else statement to select elements in different matrices?

I have been stuck on the following issue for days and would appreciate any help. I have 2 different matrices, A and B. I have a starting x and y position (xpos, ypos), and want to first, identify whether there is an element within a certain range that has a value of "0" in the matrix B. If there is an element of such kind, I want the x and y position of this element to be the new x and y position. If there aren't any elements with a value of "0", I want to select the element with the highest value within a certain range from the starting positions in matrix A. The position and this element then becomes the new x and y position. I have the following code:
for i=1:5
range=5
xpos=100
ypos=100
xstart=xpos-range
ystart=ypos-range
for gg=1:10; %double the range
for hh=1:10;
if ystart+gg <= 652 && ystart+gg>0 && xstart+hh <= 653 && xstart+hh> 0 && B(xstart+hh,ystart+gg)== 0;
xpos = xstart+hh %this becomes the new xposition
ypos = ystart+gg
else
if ystart+gg <= 652 && ystart+gg >0 && xstart+hh <= 653 && xstart + hh >0 && B(xstart+hh,ystart+gg)~= 0;
if ystart+gg <= 652 && ystart +gg>0 && xstart+hh <= 653 && xstart+hh>0 && A(ystart + gg, xstart +hh) >= 0.0;
maxtreecover = A(ystart + gg, xstart + hh)
xpos = xstart + gg %this becomes the new xpos
ypos = ystart + hh %this becomes the new ypos
end
end
end
end
end
end
The problem with this is that it does not search ALL of the elements within the range for a "0" (in the B matrix) before moving into searching the A matrix. How can I modify this code to reflect what I intend it to do?
Here is a re-write of your code which avoids the double loop. I assume all of your if conditions are so that the index remains valid (between 1 and the size of the matrix), but they wouldn't work in their current form because the indexing is done in the same line anyway! I've also addressed this using min and max conditions on xpos and ypos.
This solution gets the submatrix which spans +/- the range from your xpos and ypos. Then it evaluates the 2 conditions you describe within that submatrix:
Get the position of the first element of B which is zero
Get the position of the maximum element of A
Code is commented for details:
% Create matrices A and B
n = 100; % Size of matrices
A = rand(n);
B = rand(n);
range = 5; % "radius" of submatrix
xpos = 50; ypos = 50; % start point
% Iterate
for ii = 1:5
% Get submatrices around xpos and ypos, using min and max to ensure valid
subx = max(1,xpos-range):min(n,xpos+range);
suby = max(1,ypos-range):min(n,ypos+range);
A_sub = A(suby, subx);
B_sub = B(suby, subx);
% Find first 0 in submatrix of B, re-assign xpos/ypos if so
[yidx, xidx] = find(B_sub == 0, 1);
if ~isempty(xidx)
xpos = subx(xidx);
ypos = suby(yidx);
else
% Get max from submatrix of A
[~, idx] = max(A_sub(:));
[xidx, yidx] = meshgrid(subx, suby);
xpos = xidx(idx);
ypos = yidx(idx);
end
end

Jacobi solver going into an infinite loop

I can't seem to find a fix to my infinite loop. I have coded a Jacobi solver to solve a system of linear equations.
Here is my code:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
i =1;
for r=1:m
sum = 0;
for c=1:n
if r~=c
sum = sum + A(r,c)*x(c);
else
x(r) = (-sum + b(r))/A(r,c);
end
x(r) = (-sum + b(r))/A(r,c);
xxx end xxx
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
When I terminate the code it ends at the line with xxx
The reason why your code isn't working is due to the logic of your if statements inside your for loops. Specifically, you need to accumulate all values for a particular row that don't belong to the diagonal of that row first. Once that's done, you then perform the division. You also need to make sure that you're dividing by the diagonal coefficient of A for that row you're concentrating on, which corresponds to the component of x you're trying to solve for. You also need to remove the i=1 statement at the beginning of your loop. You're resetting i each time.
In other words:
function [x, i] = Jacobi(A, b, x0, TOL)
[m n] = size(A);
i = 0;
x = [0;0;0];
while (true)
for r=1:m
sum = 0;
for c=1:n
if r==c %// NEW
continue;
end
sum = sum + A(r,c)*x(c); %// NEW
end
x(r) = (-sum + b(r))/A(r,r); %// CHANGE
end
if abs(norm(x) - norm(x0)) < TOL;
break
end
x0 = x;
i = i + 1;
end
Example use:
A = [6 1 1; 1 5 3; 0 2 4]
b = [1 2 3].';
[x,i] = Jacobi(A, b, [0;0;0], 1e-10)
x =
0.048780487792648
-0.085365853612062
0.792682926806031
i =
20
This means it took 20 iterations to achieve a solution with tolerance 1e-10. Compare this with MATLAB's built-in inverse:
x2 = A \ b
x2 =
0.048780487804878
-0.085365853658537
0.792682926829268
As you can see, I specified a tolerance of 1e-10, which means we are guaranteed to have 10 decimal places of accuracy. We can certainly see 10 decimal places of accuracy between what Jacobi gives us with what MATLAB gives us built-in.

Double loop for each column per row in matlab

The following code does what it should and works of one column.
%% Working loop
z = HongKongPrices(1:end,114);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for i = 5:r
if z(i) == z(i-4) && z(i) == z(i-3)
zeros(i-3:i) = 1
end
end
z(zeros) = NaN
I am trying to execute the for-loop on a per column basis for HongKongPrices, however the following code fails (I am starting with three columns for time reasons).
%% Non workling loop
z = HongKongPrices(1:end,[80 85 115]);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for k = 1:c
x = z(1:end,k)
for i = 5:r
if x(i) == x(i-4) && x(i) == x(i-3)
zeros(i-3:i) = 1
end
end
end
x(zeros) = NaN
You don't need the variable x at all. You can use logical indexing in you if statement. Instead of x(i), use x(i,k) and so on. Of course you have to do the same with zeros.
z = HongKongPrices(1:end,[80 85 115]);
zeros = false(size(z));
r = size(z,1);
c = size(z,2);
for k = 1:c
for i = 5:r
if z(i,k) == z(i-4,k) && z(i,k) == z(i-3,k);
zeros(i-3:i,k) = 1
end
end
end
z(zeros) = NaN;
PS: zeros is a Matlab function, so it would be better to use another variable name. Like this you won't be able to use the zeros function in your code.

Matlab error : Subscript indices must either be real positive integers or logicals

I have the following error in MATLAB:
??? Subscript indices must either be real positive integers or
logicals.
Error in ==> Lloyd_Max at 74 D(w_count) = mean((x -
centers(xq)).^2);
This is my code :
function [ xq,centers,D ] = Lloyd_Max( x,N,min_value,max_value )
%LLOYD_MAX Summary of this function goes here
% Detailed explanation goes here
x = x';
temp = (max_value - min_value)/2^N;
count=1;
for j=0:temp:((max_value - min_value)-temp),
centers(count) = (j + j + temp )/2;
count = count + 1;
end
for i=1:length(centers),
k(i) = centers(i);
end
w_count = 0;
while((w_count < 2) || (D(w_count) - D(w_count - 1) > 1e-6))
w_count = w_count + 1;
count1 = 2;
for i=2:(count-1),
T(i) = (k(i-1) + k(i))/2;
count1 = count1 +1 ;
end
T(1) = min_value;
T(count1) = max_value;
index = 1;
for j=2:count1,
tempc = 0;
tempk = 0;
for k=1:10000,
if(x(k) >= T(j-1) && x(k) < T(j))
tempk = tempk + x(k);
tempc = tempc + 1;
end
end
k(index) = tempk;
k_count(index) = tempc;
index = index + 1;
end
for i=1:length(k),
k(i) = k(i)/k_count(i);
end
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
for i=1:10000,
cnt = 1;
for l=2:count1,
if(xq(i) > T(l-1) && xq(i) <= T(l))
xq(i) = cnt;
end
cnt = cnt +1 ;
end
end
D(w_count) = mean((x - centers(xq)).^2);
end
end
and i call it and have these inputs :
M = 10000
t=(randn(M,1)+sqrt(-1)*randn(M,1))./sqrt(2);
A= abs(t).^2;
[xq,centers,D] = Lloyd_Max( A,2,0,4 );
I tried to comment the while and the D, Results :
I got the xq and the centers all normal, xq in the 1-4 range, centers 1-4 indexes and 0.5-3.5 range.
I dont know whats going wrong here...Please help me.
Thank in advance!
MYSTERY SOVLED!
Thank you all guys for your help!
I just putted out of the while the for loop :
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
and it worked like charm.... this loop was initilizing the array again. Sorry for that. Thank you again!
There is an assignment xq(i) = x(i) somewhere in the middle of your function, but you pass A as x from outside where you calculate A from t which is sampled by randn, so you can't promise xq is an integer.
I'm not sure exactly what you are aiming to do, but your vector xq does not contain integers, it contains doubles. If you want to use a vector of indices as you do with centers(xq), all elements of the vector need to be integers.
Upon a little inspection, it looks like xq are x values, you should find some way to map them to the integer of the closest cell to which they belong (i'm guessing 'centers' represents centers of cells?)