Iterate over a vector in matlab - matlab

So I'm working on a program. I need to iterate over a vector similar to this sample = [0; 0; 0; 1; 1; 1 ; 0]. I was thinking about using loops with accumulators to build a new 2d array where column 1 is how many 0s or 1s appear and column 2 is for which token it is. But I'm new to the syntax of matlab and checking the docs i mostly see slicing. Any ideas about building the new matrix are welcome.
sample vector and output below
arr = [0; 0; 0; 1; 1; 1; 0];
tokenizeSignal(arr)
ans =
3 0
3 1
1 0

Proposed strategy (array contains only 1 and 0) :
Initialize 2 counters
count_0 = 0;
count_1 = 0;
Iterate over the whole array arr
arr = [0; 0; 0; 1; 1; 1; 0];
[n,m] = size(arr); %m is espected equal to 1
y = arr[1,1]; %first element of the array, we need a reference
Start the loop and read the current element
for i=1:n
x = arr[i,1];
start to count how many zeros or how many ones from the last group if the last element was zero or one
if (x == 0 && y == 0)
count_0 = count_0 + 1;
count_1 = 0;
else if (x == 1 && y == 1)
count_1 = count_1 + 1;
count_0 = 0;
end
print every time the value will change (last term of a "sequence")
if (x != arr[1,i+1] && count_1 > 0 && i<n)
print(count_1, '1');
else if (x != arr[1,i+1] && count_0 > 0 && i<n)
print(count_0, '0');
end
update the values and close the FOR loop
y = x;
end
out of the cycle, print the last time
if (count_1 > 0)
print(count_1, '1');
else if (count_0 >)
print(count_0, '0');
end
Of course you can change the print with store the values in a proper array.

Related

MATLAB: Limit from n to infinity for power of a matrix

I am trying to compute lim(n->inf) for D^n, where D is a diagonal matrix:
D = [1.0000 0 0 0; 0 0.6730 0 0; 0 0 0.7600 0; 0 0 0 0.7370]
n = 1
L = limit(D^n,n,inf)
This returns the error:
Undefined function 'limit' for input arguments of type 'double'.
I am sure this should result in most entries except the upper-left entry going to zero, but I need to be able to present this with MATLAB results. Is there something else I need to include in my limit function?
If your problem is to compute the inf-limit of a diagonal matrix, you'd better create your own function and handle manually the possible cases :
function Mlim = get_diag_matrix_inf_limit(M)
% get the diagonal
M_diag = diag(M);
% All possible cases
I_nan = M_diag <= -1;
I_0 = abs(M_diag) < 1;
I_1 = M_diag == 1;
I_inf = M_diag > 1;
% Update diagonal
M_diag(I_nan) = nan;
M_diag(I_0) = 0;
M_diag(I_1) = 1;
M_diag(I_inf) = Inf;
% Generate new diagonal matrix
Mlim = diag(M_diag);
end

Only allow fixed number of random points in each tile

Following up on a previous question, I have code that I think should limit the number of randomly generated points in each quadrant of the total tile; however, it is not working.
n = 4;
used = [];
k = 0;
a1_count = 0;
a2_count = 0;
a3_count = 0;
a4_count = 0;
min = 1;
max = 1;
while k<n
x = rand*2;
y = rand*2;
notvalid = 0;
if (0 <= x) && (x <= 1) && (0 <= y) && (y <= 1)
a1_count = a1_count + 1;
end
if (1 < x) && (x <= 2) && (0 <= y) && (y <= 1)
a2_count = a2_count + 1;
end
if (0 <= x) && (x <= 1) && (1 < y) && (y <= 2)
a3_count = a3_count + 1;
end
if (1 < x) && (x <= 2) && (1 < y) && (y <= 2)
a4_count = a4_count + 1;
end
%%%
if (min <= a1_count) && (a1_count <= max) && (min <= a2_count) && (a2_count <= max)...
&& (min <= a3_count) && (a3_count <= max) && (min <= a4_count) && (a4_count <= max)
notvalid=1;
end
if notvalid
continue
end
used(end+1,:) = [x;y];
k = k+1;
end
I wish to generate 4 random points, and have one in each quadrant of the total area. To do this, I have a maximum and minimum number of points in each quadrant (in this case 1), and an if statement to check that the count for each tile falls within the min and max. If it doesn't, then notvalid = 0 and the loop should begin again. This function doesn't seem to work however, as the loop finishes with 4 points total and is completely random (all the counts should = 1).
Can anyone spot where I'm going wrong?
I may be missing something, but the easiest approach would probably be something like
Select N random numbers within the x/y range of the first grid cell
Repeat for all grid cells
Here is some basic code that should create N random x/y points per grid cell
% Define the grid (for demonstration purposes)
dx = 1; dy = 1;
xrange = 0:dx:2;
yrange = 0:dy:2;
% Number of points per cell
N = 1;
[lowerx, lowery] = meshgrid(xrange(1:end-1), yrange(1:end-1));
% Store all those random numbers in a cell
data = cell(size(lowerx));
for k = 1:numel(lowerx);
% Generate 4 random points within the x/y range
xcoord = (rand(N, 1) * dx) + lowerx(k);
ycoord = (rand(N, 1) * dy) + lowery(k);
data{k} = [xcoord, ycoord];
end
disp(data)
data =
[1x2 double] [1x2 double]
[1x2 double] [1x2 double]
EDIT
To address your question directly using the code that you have provided, the logic in the code in your question is a little wonky. I have rewritten your while loop to be a little clearer so we can talk through it.
while k < n
x = rand * 2;
y = rand * 2;
if y >= 0 && y < 1
if x >= 0 && x < 1
a1_count = a1_count + 1;
else
a2_count = a2_count + 1;
end
else
if x >= 0 && x < 1
a3_count = a3_count + 1;
else
a4_count = a4_count + 1;
end
end
counts = [a1_count, a2_count, a3_count, a4_count];
notValid = all(counts >= minimum) && all(counts <= maximum);
if notValid
continue;
end
used(end+1,:) = [x;y];
k = k+1;
end
So the biggest thing is your notValid check. If you actually look at what you're checking (that all your *_count variables are within the pre-specified limits), I believe that if all of those conditions are true, then the current point is valid; however you state just the opposite.
Then you basically say, that if the current x y is valid, then add it to the used list. Well this logic is fine except that you define validity backwards as I stated before.
Ok so that aside, let's look at when you think that a point is not valid. Well, then you (correctly) go to the next iteration, but you never decrement the *_count variable. So say you had 1 point in quadrant 1 already and the second iteration through the loop it's in quadrant 1 again. Well you'd add 1 to a1_count and then see that it isn't valid (a1_count exceeds max) and go to the next loop, but a1_count stays at 2 despite really only having 1 because you just rejected it.
Now, all of that aside. Let's consider the first time through your loop and look at your validity check. Since you only add one point. Your validity check can never pass (if implemented correctly) because all *_count variables except the one that was just incremented will be less than the min.
So I think what happened is you probably did the validity check correctly at first, ended up with an infite while loop, and then negated that check, didn't get an infinite loop, but as a result got an incorrect solution.
The solution that you are getting currently, is literally the first 4 times through the while loop due to the incorrect logic.
If you really like your current approach, we can clean up the code to be correct.
n = 4;
used = zeros(0,2);
minimum = 1;
maximum = 1;
counts = [0 0 0 0];
while true
x = rand * 2;
y = rand * 2;
if y >= 0 && y < 1
if x >= 0 && x < 1
quadrant = 1;
else
quadrant = 2;
end
else
if x >= 0 && x < 1
quadrant = 3;
else
quadrant = 4;
end
end
% Check to see if we can even add this point
if counts(quadrant) + 1 > maximum
continue;
end
counts(quadrant) = counts(quadrant) + 1;
used = cat(1, used, [x, y]);
isComplete = all(counts >= minimum & counts <= maximum) && ...
size(used, 1) == n;
if isComplete
break
end
end

Generate random points - limit number per tile of total area

I am trying to create a set of random points, but limit the number in each say, 1/4th, of the total area. So imagining my x & y ranged from 0 to 2, and 0 to 2, I would only get a certain number of randomly generated points within the tile (0
So far, I thought I could just create an if statement for each tile, then if the randomly generated point falls within the tile, it gets added to a count, which then if the count exceeds or is not great enough for that tile, another point will be generated and checked. This count method doesn't seem to work, instead of each of the counts going up, I get only the count for tile 4 to increase.
n = 8;
used = [];
k = 0;
a1_count = 0;
a2_count = 0;
a3_count = 0;
a4_count = 0;
while k<n
x = rand*2;
y = rand*2;
if 0 < x < 1 && 0 < y < 1
a1_count = a1_count + 1;
end
if 1 < x < 2 && 0 < y < 1
a2_count = a2_count + 1;
end
if 0 < x < 1 && 1 < y < 2
a3_count = a3_count + 1;
end
if 1 < x < 2 && 1 < y < 2
a4_count = a4_count + 1;
end
used(end+1,:) = [x;y];
k = k+1;
end
If the counts worked correctly, I would then have a min & max, and then use an if statement to check if a count is outwith the min & max, and if so use the continue statement to go on or not.
Can anyone tell me why the count is not increasing for each area? If I run this code, I get a1_count, a2_count, a3_count = 0, while a4_count = 8, even though the points lie within the a1, a2 and a3 boundaries.
An expression of the form 0 < x < 1 needs to be written as 0 < x && x < 1.
0 < x < 1 is syntactically valid so therefore does not flag up any warning or error: it is the same as (0 < x) < 1. Note that (0 < x) is itself either 0 or 1.
This explains why 1 < x < 2 && 1 < y < 2 always evaluates to 1 and therefore a4_count is always increased: 1 < x < 2 is (1 < x) < 2 which is always 1, irrespective of the value of x. Similarly for 1 < y < 2.

Getting the error "Subscript indices must either be real positive integers or logicals" despite the workspace indicating my varirable all = 1

I am getting this error in MatLab when trying to fill in an array. MatLab is saying that the assignment B(j, 1) = z(z-counter) contains a negative or non integer value. However when I look at the variables values in the workspace after trying to execute the code.
j =1, counter =1, z =1
for j= 1:1:totalSizeOfMatrix
if( j <= totalNumberInBottom)
if( mod(j, lengthOfBottomRow) == 1)
counter= counter +1;
end
z = mod(j,lengthOfBottomRow);
B(j,1) = z(z-counter);
end
if( j > totalNumberInBottom && j <= totalNumberNotInTop)
if( mod(j, lengthOfSecondRow) == 1)
counter= counter +1;
end
z = mod(j,lengthOfSecondRow);
B(j,1) = z(z-counter);
end
if( j > totalNumberInBottom)
if( mod(j, lengthOfTopRow) == 1)
counter= counter +1;
end
z = mod(j,lengthOfTopRow);
B(j,1) = z(z-counter);
end
end
If z = 1 and counter = 1, then z - counter is zero.
Therefore, z(z-counter) is trying to access z(0), which is an error.

Perceptron training in Matlab

I am trying to create a simple perceptron training function in MATLAB. I want to return the weights when no errors are found.
Here is the data I want to classify.
d = rand(10,2);
figure
labels = ones(10,1);
diff = d(:,1) + d(:,2) - 1;
labels( diff + 1 >= 1) = 2;
pathWidth = 0.05;
labels( abs(diff) < pathWidth) = [];
d(abs(diff) < pathWidth,:) = [];
plot(d(labels == 1,1),d(labels == 1,2),'k.','MarkerSize',10)
plot(d(labels == 2,1),d(labels == 2,2),'r.','MarkerSize',10)
It produces a labelled data set, where the division between the two classes (red, black) are more visible if you increase the number of points for d.
For my perceptron function I pass the data (d) and labels. I have 3 inputs, the x values, y values and bias which is one. Each input has a random weight between 0 and 1 assigned. Note that the dataset d I have named Z in the perceptron function.
I did use a sigmoid activation function but that would run once through the while loop and always return true after that, the sigmoid function also gave me values of either inf or 1. Below I am using just a threshold activation but it seems to continually loop and not returning my weights. I think the problem may lie in the if-statement below
if(v >= 0 && labels(i) == 1 || v < 0 && labels(i) == 2)
Perceptron function:
function perceptron(data,labels)
sizea = numel(data(:,1));
weights = rand(sizea,3);
Z = data(:,:)
eta = 0.5;
errors = 1;
count = 0;
while errors > 0
errors = 0;
v = sum((1*weights(1,1)) + (Z(:,1)*weights(1,2)) + (Z(:,2)*weights(1,3)));
if v >= 1
v = 1;
else
v = 0;
end
count = count + 1
for i = 1:sizea % for each object in dataset
if(v == 1 && labels(i) == 1 || v == 0 && labels(i) == 2)
errors = 1;
weights(1,1) = weights(1,1) - (2*v-1) * eta * 1;
weights(1,2) = weights(1,2) - (2*v-1) * eta * Z(i,1);
weights(1,3) = weights(1,3) - (2*v-1) * eta * Z(i,2);
v = sum((1*weights(1,1)) + (Z(:,1)*weights(1,2)) + (Z(:,2)*weights(1,3)));
if v >= 1
v = 1;
else
v = 0;
end
end
end
end
There are two major problems in your code:
You need to update v in your loop every time your weights vectors are updated.
It seems like you have 10 training set. So you have to update v sequentially in the loop instead of simultaneously. Keep iterating for every training set, update weights, then use the new weights to calculate the v for the next training set, so on and so forth, until there is no error (errors = 0 in your case).
Minor issue:
if(v >= 0 && labels(i) == 1 || v < 0 && labels(i) == 2)
should be
if(v == 1 && labels(i) == 1 || v == 0 && labels(i) == 2)
You may refer to this example to get more details of the algorithm.