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.
Related
Could someone explain how to create a pseudo number generator that has a range of 1 to 51 and can have its value placed within something like the for loop. This has to be in System Verilog and synthesizable. I have read about some CRC and LFSRs but was not quite sure how to modify them to fit it within the specified values I needed (1-52) and how to fit it within a for loop as most examples took up an entire module.
Thank you for your time.
initial begin
for(int i = 0; i < 52; i++) begin
int j = // insert PSEUDO RANDOM NUM GEN 0 to 51
if(array[j] == 0)begin
i = i-1;
continue;
end
else
array2[i] = array[j];
array[j] = 0;
end
end
(array and array2 both have 52 values of bit size 4)
I don't know what is your application, but what you could do is to generate numbers in the modular ring mod 53 (53 is a prime number). Since you did not mention any other requirement I will take the simplest generator I could imagine, that can be performed without multiplications and will generate numbers, 1 <= n < 52.
function [5:0] next_item(input logic [5:0] v);
if(v < 26) begin
next_item = (v << 1); // 2 * v % 53 = 2 * v
end
else if(v > 26) begin
// (2 * v) % 53 = (2 * v - 52 - 1) % 53 = 2 * (v - 26) - 1
next_item = (((v - 26) << 2) - 1);
end
else begin
// v = 26, you want to exclude 2 * v % 53 = 52, so we skip it
// by applying the next item again, and it will be
next_item = 51;
end
endfunction
And you could use it like this
parameter SEED = 20; // any number 1 <= N < 52 you like
initial begin
int j = SEED;
for(int i = 0; i < 52; i++) begin
if(array[j-1] == 0)begin
i = i-1;
continue;
end
else begin
array2[i] = array[k];
end
j = next_item(j);
end
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.
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
I used the following simple code to check the properties of elseif command in MATLAB:
x = 10;
if x < 0
y = x;
elseif 0 <= x < 2
y = 3*x;
elseif x >= 2
y = 8*x;
end
y
I would have expected the result of this to be 80 since x >= 2. But something amazing happened! The result is 30, not 80!
But why? Any ideas?
Update: when I change the code (as recommended in the answers) to
x = 10;
if x < 0
y = x;
elseif (0 <= x) && ( x < 2 )
y = 3*x;
elseif x >= 2
y = 8*x;
end
y
I get 80 as expected. It's that double condition that threw me off.
When you write
if 0 <= x < 2
you are really writing (without realizing it)
if (0 <= x) < 2
Which is evaluated as
if (true) < 2
which is true, since true evaluates to 1.
So here is what is happening, line by line:
x = 10; % x is set to 10
if x < 0 % false
y = x; % not executed
elseif 0 <= x < 2 % condition is (true) < 2, thus true
y = 3*x; % y is set to 3*x, i.e. 30
elseif x >= 2 % since we already passed a condition, this is not evaluated
y = 8*x; % skipped
end % end of composite if
y % display the value of y - it should be 30
As an aside, when you use scalars, you should really use the && operator, not the & operator. See for example What's the difference between & and && in MATLAB?
0 <= x < 2 doesn't behave as you may expect. Use (0 <= x) & (x < 2)
How does 0 <= x < 2 behave? It is evaluated from left to right. First 0 <= x gives 1 (true), and then 1 < 2 gives 1 (true). So the condition gives true, not false as you would expect.
Since the second condition in your code (0 <= x < 2) is true, you get a value 30 for y. Changing the condition to (0 <= x) & (x < 2) you get a value 80 for y.
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.