randcase weight behaviour unexpected - system-verilog

class test1;
function test_randcase();
for (int idx=0; idx < 10; idx++) begin
randcase
50: begin
$display("displaying from first cases");
end
50: begin
$display("displaying from second case");
end
endcase
end
endfunction
endclass
program main;
initial begin
test1 t1=new();
t1.test_randcase();
end
endprogram
Since each case is equally weighed here (50/100=0.5) so the expectation is that I would see each display 5 times in total. However, I see "first case" print 6 times and "second case" print 4 times. If this is the behavior of randcase, then how would I achieve my intention of equal weight? I used vcs compiler for this execution.
output:
displaying from second case
displaying from first cases
displaying from first cases
displaying from first cases
displaying from first cases
displaying from second case
displaying from first cases
displaying from second case
displaying from second case
displaying from first cases

Looking at this problem another way, suppose you had to choose a completely random 10-bit number where each bit has a 50% chance of being 0 or 1. There are 1024 possible numbers with a 1/1024 chance of having 10 1's and a 1/1024 chance of having 10 0's. And the odds of choosing a number with exactly 5 1's and 5 0's is around 25%. If you run more iterations, your randcase distribution would approach 0.50, but the odds of getting an exact 0.5 distribution diminish.
If your requirement is getting an exact distribution, you need to know upfront how many iterations you plan to have. There are several approaches you could take, one of which I can show you
class test1;
enum {FIRST, SECOND} itor[10];
function new;
itor[0:4] = '{5{FIRST}};
itor[5:9] = '{5{SECOND}};
endfunction
function void test_randcase();
itor.shuffle();
foreach(itor[i]) begin
case(itor[i])
FIRST: begin
$display("displaying from first cases");
end
SECOND: begin
$display("displaying from second case");
end
endcase
end
endfunction
endclass
module main;
test1 t1=new();
initial repeat(10)begin
$display("---");
t1.test_randcase();
end
endmodule
Other ways are shown in my paper from DVCon 2020, SystemVerilog Constraints: Appreciating What You Forgot in School to Get Better Results

Related

system verilog 2 dimensional dynamic array randomization

I am trying to use system verilog constraint solver to solve the following problem statement :
We have N balls each with unique weight and these balls need to be distributed into groups , such that weight of each group does not exceed a threshold ( MAX_WEIGHT) .
Now i want to find all such possible solutions . The code I wrote in SV is as follows :
`define NUM_BALLS 5
`define MAX_WEIGHT_BUCKET 100
class weight_distributor;
int ball_weight [`NUM_BALLS];
rand int unsigned solution_array[][];
constraint c_solve_bucket_problem
{
foreach(solution_array[i,j]) {
solution_array[i][j] inside {ball_weight};
//unique{solution_array[i][j]};
foreach(solution_array[ii,jj])
if(!((ii == i) & (j == jj))) solution_array[ii][jj] != solution_array[i][j];
}
foreach(solution_array[i,])
solution_array[i].sum() < `MAX_WEIGHT_BUCKET;
}
function new();
ball_weight = {10,20,30,40,50};
endfunction
function void post_randomize();
foreach(solution_array[i,j])
$display("solution_array[%0d][%0d] = %0d", i,j,solution_array[i][j]);
$display("solution_array size = %0d",solution_array.size);
endfunction
endclass
module top;
weight_distributor weight_distributor_o;
initial begin
weight_distributor_o = new();
void'(weight_distributor_o.randomize());
end
endmodule
The issue i am facing here is that i want the size of both the dimentions of the array to be randomly decided based on the constraint solution_array[i].sum() < `MAX_WEIGHT_BUCKET; . From my understanding of SV constraints i believe that the size of the array will be solved before value assignment to the array .
Moreover i also wanted to know if unique could be used for 2 dimentional dynamic array .
You can't use the random number generator (RNG) to enumerate all possible solutions of your problem. It's not built for this. An RNG can give you one of these solutions with each call to randomize(). It's not guaranteed, though, that it gives you a different solution with each call. Say you have 3 solutions, S0, S1, S2. The solver could give you S1, then S2, then S1 again, then S1, then S0, etc. If you know how many solutions there are, you can stop once you've seen them all. Generally, though, you don't know this beforehand.
What an RNG can do, however, is check whether a solution you provide is correct. If you loop over all possible solutions, you can filter out only the ones that are correct. In your case, you have N balls and up to N groups. You can start out by putting each ball into one group and trying if this is a correct solution. You can then put 2 balls into one group and all the other N - 2 into a groups of one. You can put two other balls into one group and all the others into groups of one. You can start putting 2 balls into one group, 2 other balls into one group and all the other N - 4 into groups of one. You can continue this until you put all N balls into the same group. I'm not really sure how you can easily enumerate all solutions. Combinatorics can help you here. At each step of the way you can check whether a certain ball arrangement satisfies the constraints:
// Array describing an arrangement of balls
// - the first dimension is the group
// - the second dimension is the index within the group
typedef unsigned int unsigned arrangement_t[][];
// Function that gives you the next arrangement to try out
function arrangement_t get_next_arrangement();
// ...
endfunction
arrangement = get_next_arrangement();
if (weight_distributor_o.randomize() with {
solution.size() == arrangement.size();
foreach (solution[i]) {
solution[i].size() == arrangement[i].size();
foreach (solution[i][j])
solution[i][j] == arrangement[i][j];
}
})
all_solutions.push_back(arrangement);
Now, let's look at weight_distributor. I'd recommend you write each requirement in an own constraint as this makes the code much more readable.
You can shorten you uniqueness constraint that you wrote as a double loop to using the unique operator:
class weight_distributor;
// ...
constraint unique_balls {
unique { solution_array };
}
endclass
You already had a constraint that each group can have at most MAX_WEIGHT in it:
class weight_distributor;
// ...
constraint max_weight_per_group {
foreach (solution_array[i])
solution_array[i].sum() < `MAX_WEIGHT_BUCKET;
}
endclass
Because of the way array sizes are solved, it's not possible to write constraints that will ensure that you can compute a valid solution using simple calls randomize(). You don't need this, though, if you want to check whether a solution is valid. This is due to the constraints on array sizes in the between arrangement and solution_array.
Try this.!
class ABC;
rand bit[3:0] md_array [][]; // Multidimansional Arrays with unknown size
constraint c_md_array {
// First assign the size of the first dimension of md_array
md_array.size() == 2;
// Then for each sub-array in the first dimension do the following:
foreach (md_array[i]) {
// Randomize size of the sub-array to a value within the range
md_array[i].size() inside {[1:5]};
// Iterate over the second dimension
foreach (md_array[i][j]) {
// Assign constraints for values to the second dimension
md_array[i][j] inside {[1:10]};
}
}
}
endclass
module tb;
initial begin
ABC abc = new;
abc.randomize();
$display ("md_array = %p", abc.md_array);
end
endmodule
https://www.chipverify.com/systemverilog/systemverilog-foreach-constraint

Ruby: dealing with booleans: How to address not using military time for a clock Class

TDD
gem 'minitest', '~> 5.2'
require 'minitest/autorun'
require 'minitest/pride'
require_relative 'clock'
class ClockTest < Minitest::Test
def test_start_at_6
clock = Clock.new
assert_equal 6, clock.time
end
def test_passage_of_time
clock = Clock.new
clock.wait
assert_equal 7, clock.time
3.times { clock.wait }
assert_equal 10, clock.time
end
def test_clocks_are_not_military_time
clock = Clock.new
8.times { clock.wait }
assert_equal 2, clock.time
end
end
CODE
class Clock
attr_reader :time
def initialize
#time = 6
end
def wait(time = 1)
#time += time
end
def not_military_time
#time += (time - 10)
end
end
Can anyone guide me into figuring out how to address that the clocks are not in military time? It's coming as Expected : 2 , Actual : 14. I feel like there needs to be some of subtraction going in order to address the clock saying 2 instead of 14.
I know what I have in the code does not work, but am I on the right track?
If you look through all of the tests you'll see that apart from test_start_at_6 each test essentially calls wait some number of times and then checks for the right time in clock.time.
If you look at your code, clock.time is generated by attr_reader and so all it will ever do is return the current value of #time. So this leaves you with wait as a place to implement the behaviour needed to make the tests pass.
One other thing to notice is that you're currently overcomplicating the wait method. It's never called with any parameters and so the time parameter isn't needed. So to start simplify that to just:
def wait
#time += 1
end
Next, step away from the code and make a little list showing for each current time what the next time needs to be after wait is called. You can then think about how to change wait so that it matches that required behaviour.
In terms of whether to use an if or a case statement, everything that you could achieve using a case statement can also be done with an if as an alternative. It's best to think about the most common use of a case statement which is for checking the same variable for various possible values. i.e. the case statement
case #time
when 1
puts "One o'clock"
when 2
puts "Two o'clock"
else
puts "Later!"
end
is the same as:
if #time == 1
puts "One o'clock"
elsif #time == 2
puts "Two o'clock"
else
puts "Later!"
end
Often when you're just working out what some logic needs to be you'll write it as an if statement and then once it's working realise that it can more elegantly be expressed as a case statement. In this exercise an if should be fine.

MATLAB Structure array blackjack

I'm writing a program to play blackjack and one of the functions calculates the score. It takes in an input which is a structure array of cards and one of the attributes is value (for an ace the value is 11). My function is supposed to determine if the total of the values is over 21 and if 1 of the cards is an ace, then the ace's value is changed to 1. Can anyone help me figure this out please?
for index=1:length(input)
if(input(input).value == 11)
input(index).value = 1;
end;
end;
You're not actually summing the cards in your original snippet. You also seem to have a typo in input(input), I think this should be input(index). If you wanted to do it with a for loop like you have, you'd do something like this:
total = 0;
for index=1:length(input)
if(input(index).value == 11)
input(index).value = 1;
end;
total = total + input(index);
end;
The more MATLAB way of doing things would be to avoid loops by using the sum in-built command.

Save outputs of nested for loops in MATLAB

I have the following codes which I wish to have an output matrix Rpp of (10201,3). I run this code (which takes a bit long) then I check the matrix size of Rpp and I see (1,3), I tried so many things I couldn't find any proper way. The logic of the codes is to take the 6 values (contain 4 constant values and 2 variable values (chosen from 101 values)) and make the calculation for 3 different i1 and store every output vector of 3 in a matrix with (101*101 (pairs of those 2 variable values)) rows and 3 (for each i1) columns.
I appreciate your help
Vp1=linspace(3000,3500,101);
Vp2=3850;
rho1=2390;
rho2=2510;
Vs1=linspace(1250,1750,101);
Vs2=2000;
i1=[10 25 40];
Rpp = zeros(length(Vp1)*length(Vs1),length (i1));
for n=1:length(Vp1)*length(Vs1)
for m=1:length (i1)
for l=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(l);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(l)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(l)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp=((b.*(cos(i1)/Vp1(l))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(l))).*(cos(j2)/Vs2)).*H.*p.^2)./D
end
end
end
end
Try this. You 2 outer loops didn't do anything. You never used m or n so I killed those 2 loops. Also you just kept overwriting Rpp on every loop so your initialization of Rpp didn't do anything. I added an index var to assign the results to the equation to what I think is the correct part of Rpp.
Vp1=linspace(3000,3500,101);
Vp2=3850;
rho1=2390;
rho2=2510;
Vs1=linspace(1250,1750,101);
Vs2=2000;
i1=[10 25 40];
Rpp = zeros(length(Vp1)*length(Vs1),length (i1));
index = 1;
for l=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(l);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(l)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(l)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp(index,:)=((b.*(cos(i1)/Vp1(l))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(l))).*(cos(j2)/Vs2)).*H.*p.^2)./D;
index = index+1;
end
end
Results:
>> size(Rpp)
ans =
10201 3
The way you use the for loop is wrong. You're running the calculation for length(Vp1)*length(Vs1) * length (i1) * length(Vp1) * length(Vs1) times. Here's the correct way. I changed l into lll just so I won't confuse it with the number 1. In each iteration of the first for loop, you're running length(Vs1) times, and you need to assign the result (a 1X3 array) to the Rpp by using a row number specified by k+(lll-1)*length(Vp1).
for lll=1:length(Vp1)
for k=1:length(Vs1)
p=sin(i1)/Vp1(lll);
i2=asin(p*Vp2);
j1=asin(p*Vs1(k));
j2=asin(p*Vs2);
a=rho2*(1-2*Vs2^2*p.^2)-rho1*(1-2*Vs1(k).^2*p.^2);
b=rho2*(1-2*Vs2^2*p.^2)+2*rho1*Vs1(k)^2*p.^2;
c=rho1*(1-2*Vs1(k)^2*p.^2)+2*rho2*Vs2^2*p.^2;
d=2*(rho2*Vs2^2-rho1*Vs1(k)^2);
E=b.*cos(i1)./Vp1(lll)+c.*cos(i2)/Vp2;
F=b.*cos(j1)./Vs1(k)+c.*cos(j2)/Vs2;
G=a-d*(cos(i1)/Vp1(lll)).*(cos(j2)/Vs2);
H=a-d*(cos(i2)/Vp2).*(cos(j1)/Vs1(k));
D=E.*F+G.*H.*p.^2;
Rpp(k+(lll-1)*length(Vp1),:)=((b.*(cos(i1)/Vp1(lll))-c.*cos((i2)/Vp2)).*F-(a+d*((cos(i1)/Vp1(lll))).*(cos(j2)/Vs2)).*H.*p.^2)./D;
end
end

Using For and While Loops to Determine Who to Hire MATLAB

It's that time of the week where I realize just how little I understand in MATLAB. This week, we have homework on iteration, so using for-loops and while-loops. The problem I am currently experiencing difficulties with is one where I have to write a function that decides who to hire somebody. I'm given a list of names, a list of GPAs and a logical vector that tells me whether or not a student stayed to talk. What I have to output is the names of people to hire and the time they spent chatting with the recruiter.
function[candidates_hire, time_spent] = CFRecruiter(names, GPAs, stays_to_talk)
In order to be hired, a canidate must have a GPA that is higher than 2.5 (not inclusive). In order to be hired, the student must stick around to talk, if they don't talk, they don't get hired. The names are separated by a ', ' and the GPAs is a vector. The time spent talking is determined by:
Time in minutes = (GPA - 2.5) * 4;
My code so far:
function[candidates_hire, time_spent] = CFRecruiter(names, GPAs, stays_to_talk)
candidates = strsplit(names, ', ');
%// My attempt to split up the candidates names.
%// I get a 1x3 cell array though
for i = 1:length(GPAs)
%// This is where I ran into trouble, I need to separate the GPAs
student_GPA = (GPAs(1:length(GPAs)));
%// The length is unknown, but this isn't working out quite yet.
%// Not too sure how to fix that
return
end
time_spent = (student_GPA - 2.5) * 4; %My second output
while stays_to_talk == 1 %// My first attempt at a while-loop!
if student_GPA > 2.5
%// If the student has a high enough GPA and talks, yay for them
student = 'hired';
else
student = 'nothired'; %If not, sadface
return
end
end
hired = 'hired';
%// Here was my attempt to get it to realize how was hired, but I need
%// to concatenate the names that qualify into a string for the end
nothired = 'nothired';
canidates_hire = [hired];
What my main issue is here is figuring out how to let the function know them names(1) has the GPA of GPAs(1). It was recommended that I start a counter, and that I had to make sure my loops kept the names with them. Any suggestions with this problem? Please and thank you :)
Test Codes
[Names, Time] = CFRecruiter('Jack, Rose, Tom', [3.9, 2.3, 3.3],...
[false true true])
=> Name = 'Tom'
Time = 3.2000
[Names, Time] = CFRecruiter('Vatech, George Burdell, Barnes Noble',...
[4.0, 2.5, 3.6], [true true true])
=> Name = 'Vatech, Barnes Noble'
Time = 10.4000
I'm going to do away with for and while loops for this particular problem, mainly because you can solve this problem very elegantly in (I kid you not) three lines of code... well four if you count returning the candidate names. Also, the person who is teaching you MATLAB (absolutely no offense intended) hasn't the faintest idea of what they're talking about. The #1 rule in MATLAB is that if you can vectorize your code, do it. However, there are certain situations where a for loop is very suitable due to the performance enhancements of the JIT (Just-In-Time) accelerator. If you're curious, you can check out this link for more details on what JIT is about. However, I can guarantee that using loops in this case will be slow.
We can decompose your problem into three steps:
Determine who stuck around to talk.
For those who stuck around to talk, check their GPAs to see if they are > 2.5.
For those that have satisfied (1) and (2), determine the total time spent on talking by using the formula in your post for each person and add up the times.
We can use a logical vector to generate a Boolean array that simultaneously checks steps #1 and #2 so that we can index into our GPA array that you are specifying. Once we do this, we simply apply the formula to the filtered GPAs, then sum up the time spent. Therefore, your code is very simply:
function [candidates_hire, time_spent] = CFRecruiter(names, GPAs, stays_to_talk)
%// Pre-processing - split up the names
candidates = strsplit(names, ', ');
%// Steps #1 and #2
filtered_candidates = GPAs > 2.5 & stays_to_talk;
%// Return candidates who are hired
candidates_hire = strjoin(candidates(filtered_candidates), ', ');
%// Step #3
time_spent = sum((GPAs(filtered_candidates) - 2.5) * 4);
You had the right idea to split up the names based on the commas. strsplit splits up a string that has the token you're looking for (which is , in your case) into separate strings inside a cell array. As such, you will get a cell array where each element has the name of the person to be interviewed. Now, I combined steps #1 and #2 into a single step where I have a logical vector calculated that tells you which candidates satisfied the requirements. I then use this to index into our candidates cell array, then use strjoin to join all of the names together in a single string, where each name is separated by , as per your example output.
The final step would be to use the logical vector to index into the GPAs vector, grab those GPAs from those candidates who are successful, then apply the formula to each of these elements and sum them up. With this, here are the results using your sample inputs:
>> [Names, Time] = CFRecruiter('Jack, Rose, Tom', [3.9, 2.3, 3.3],...
[false true true])
Names =
Tom
Time =
3.2000
>> [Names, Time] = CFRecruiter('Vatech, George Burdell, Barnes Noble',...
[4.0, 2.5, 3.6], [true true true])
Names =
Vatech, Barnes Noble
Time =
10.4000
To satisfy the masses...
Now, if you're absolutely hell bent on using for loops, we can replace steps #1 and #2 by using a loop and an if condition, as well as a counter to keep track of the total amount of time spent so far. We will also need an additional cell array to keep track of those names that have passed the requirements. As such:
function [candidates_hire, time_spent] = CFRecruiter(names, GPAs, stays_to_talk)
%// Pre-processing - split up the names
candidates = strsplit(names, ', ');
final_names = [];
time_spent = 0;
for idx = 1 : length(candidates)
%// Steps #1 and #2
if GPAs(idx) > 2.5 && stays_to_talk(idx)
%// Step #3
time_spent = time_spent + (GPAs(idx) - 2.5)*4;
final_names = [final_names candidates(idx)];
end
end
%// Return candidates who are hired
candidates_hire = strjoin(final_names, ', ');
The trick with the above code is that we are keeping an additional cell array around that stores those candidates that have passed. We will then join all of the strings together with a , between each name as we did before. You'll also notice that there is a difference in checking for steps #1 and #2 between the two methods. In particular, there is a & in the first method and a && in the second method. The single & is for arrays and matrices while && is for single values. If you don't know what that symbol is, that is the symbol for logical AND. This means that something is true only if both the left side of the & and the right side of the & are both true. In your case, this means that someone who has a GPA of > 2.5 and stays to talk must both be true if they are to be hired.