约束问题:在具有特定数字匹配的数组中选择数字
Constraint issue: pick number within array with specific number match
这是我上次面试的问题如下:
问。 (约束随机化)考虑这个page
的彩票规则
- 给定将赢得头奖的一组六个号码作为输入,尝试并实施约束以生成一组赢得第二高奖项的号码,恰好匹配六个头奖号码中的 5 个号码。
以下是我的代码link to EDA playground:
测试台:
module tb;
initial begin
Pick p = new();
p.randomize();
$display("\nPicked result:");
for (int i=0; i<`NUM_JACKPOT; i++)
$write("%0d ", p.jackpot_result[i]);
$write("\n");
end
endmodule
设计代码:
`define NUM_JACKPOT 6
class Lottery;
randc int six_jackpot_nums[`NUM_JACKPOT];
constraint rand_jackpot {
foreach (six_jackpot_nums[i])
six_jackpot_nums[i] inside {[1:49]};
}
endclass
class Pick;
randc int six_jackpot_nums[`NUM_JACKPOT];
randc int jackpot_result [`NUM_JACKPOT];
int award_2nd_hi = `NUM_JACKPOT -1;
function pre_randomize();
Lottery l = new();
l.randomize();
$display("Jackpot bingo:");
for (int i=0; i<`NUM_JACKPOT; i++) begin
six_jackpot_nums[i] = l.six_jackpot_nums[i];
$write("%0d ", l.six_jackpot_nums[i]);
end
endfunction
constraint pick_jackpot{
foreach (jackpot_result[i])
jackpot_result[i] inside {[1:49]};
award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5]));
}
function int match(int v);
int tmp[$];
tmp = six_jackpot_nums.find(x) with (x == v);
if(tmp.size != 0) return 1;
return 0;
endfunction
endclass
以目前的状态,我可以成功创建六号头奖。然而,当我创建第二高的数字对时,我遇到了冲突。请指教
结果:
xmsim: *W,RNDOCS: These constraints contribute to the set of conflicting constraints:
award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5])); (./design.sv,31)
xmsim: *W,RNDOCS: These variables contribute to the set of conflicting constraints:
Var_Name Type Status Current_Value Source
-----------------------------------------------------------------------------------------------------
award_2nd_hi (S32) STATE VAR 5 (0x5) ./design.sv ; line 16
jackpot_result[0] (S32) SOLVED EARLY 32 (0x20) ./design.sv ; line 15
jackpot_result[1] (S32) SOLVED EARLY 47 (0x2f) ./design.sv ; line 15
jackpot_result[2] (S32) SOLVED EARLY 21 (0x15) ./design.sv ; line 15
jackpot_result[3] (S32) SOLVED EARLY 40 (0x28) ./design.sv ; line 15
jackpot_result[4] (S32) SOLVED EARLY 1 (0x1) ./design.sv ; line 15
jackpot_result[5] (S32) SOLVED EARLY 27 (0x1b) ./design.sv ; line 15
match( .v( jackpot_result[0] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[1] ) ) (S32) SOLVED EARLY 1 (0x1) ./design.sv ; line 31
match( .v( jackpot_result[2] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[3] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[4] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[5] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
Jackpot bingo:
31 49 43 24 47 8
Picked result:
0 0 0 0 0 0
这是一种更简单的方法,可以避免所有警告(以及其他模拟器上的错误)。随机生成一组 6 个获胜者。此外,随机选择一个获胜者,用失败的号码代替。使用 post_randomize
,创建一组失败者,然后随机选择其中一个并替换其中一个获胜者。
`define NUM_JACKPOT 6
class Lottery;
rand int six_jackpot_nums[`NUM_JACKPOT];
int jackpot_result [`NUM_JACKPOT];
int losers [$];
rand int unsigned idx;
function void post_randomize;
for (int i=1; i<50; i++) begin
if (!(i inside {six_jackpot_nums})) losers.push_back(i);
end
losers.shuffle();
for (int i=0; i<`NUM_JACKPOT; i++) begin
jackpot_result[i] = (i == idx) ? losers[0] : six_jackpot_nums[i];
end
endfunction
constraint rand_jackpot {
unique {six_jackpot_nums};
foreach (six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
idx inside {[1:`NUM_JACKPOT]};
}
endclass
module tb;
Lottery lot;
initial begin
lot = new();
void'(lot.randomize());
$display("\nPicked result:");
for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.six_jackpot_nums[i]);
$display("\nJackpot bingo:");
for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.jackpot_result [i]);
$display;
end
endmodule
示例输出:
Picked result:
48 4 46 3 17 16
Jackpot bingo:
48 4 21 3 17 16
这里,46被21代替了。
要解决 中提到的 randc
问题,请使用 unique
约束关键字。
声明 randc 不能保证数组元素在单一随机化中是唯一的。所以我添加了一个约束 unique_cons 来解决这个问题。
`define NUM_JACKPOT 6
class Lottery;
rand int six_jackpot_nums[`NUM_JACKPOT];
rand int jackpot_result [`NUM_JACKPOT];
rand int missed;
constraint unique_cons {
foreach (six_jackpot_nums[i])
foreach(six_jackpot_nums[j])
if(i!=j) six_jackpot_nums[i]!=six_jackpot_nums[j];
}
constraint valid_cons {
foreach (six_jackpot_nums[i]){
six_jackpot_nums[i] inside {[1:49]};
jackpot_result[i] inside {[1:49]};
}
}
constraint missed_cons {
missed inside {[0:`NUM_JACKPOT-1]} ;
}
constraint rand_jackpot {
foreach (six_jackpot_nums[i])
if(i==missed)
~(jackpot_result[i] inside {six_jackpot_nums});
else
jackpot_result[i] == six_jackpot_nums[i];
}
endclass
结果:
Jackpot bingo:
30 44 12 37 1 22
Picked result:
30 44 12 37 1 9
Jackpot bingo:
40 12 20 46 8 2
Picked result:
40 12 20 5 8 2
Jackpot bingo:
29 23 13 41 48 28
Picked result:
29 39 13 41 48 28
Jackpot bingo:
8 14 35 19 28 39
Picked result:
8 20 35 19 28 39
第一个答案的好电话,unique 约束关键字已在 systemverilog-2012 中启用。
您应该尽可能寻找避免 pre/post_randomize()
的解决方案。这使得在一次解决所有约束和随机变量时更容易覆盖或添加更多约束。
parameter int JACKPOT_NUM = 6;
class Lottery;
rand int six_jackpot_nums[JACKPOT_NUM];
rand int pick_result_nums[JACKPOT_NUM];
constraint jack_rand {
unique {six_jackpot_nums};
foreach(six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
unique {pick_result_nums};
foreach(pick_result_nums[i]) pick_result_nums[i] inside {[1:49]};
}
constraint pick5 {
pick_result_nums.sum() with (int'(item == six_jackpot_nums[item.index])) == 5;
}
endclass
module tb;
initial begin
static Lottery l = new();
repeat(3) begin
assert(l.randomize());
$display("\nBingo result:");
foreach(l.six_jackpot_nums[i])
$write("%0d ", l.six_jackpot_nums[i]);
$display("\nPicked result:");
foreach(l.six_jackpot_nums[i])
$write("%0d ", l.pick_result_nums[i]);
$write("\n");
end
end
endmodule
这样做可以让您添加更多限制条件,例如“不匹配的所选号码必须比中奖号码大一”。这当然使 49 不会被选为错过的累积奖金号码,但它也不会错过任何两个连续累积奖金号码中的第一个。
这是我上次面试的问题如下:
问。 (约束随机化)考虑这个page
的彩票规则- 给定将赢得头奖的一组六个号码作为输入,尝试并实施约束以生成一组赢得第二高奖项的号码,恰好匹配六个头奖号码中的 5 个号码。
以下是我的代码link to EDA playground:
测试台:
module tb;
initial begin
Pick p = new();
p.randomize();
$display("\nPicked result:");
for (int i=0; i<`NUM_JACKPOT; i++)
$write("%0d ", p.jackpot_result[i]);
$write("\n");
end
endmodule
设计代码:
`define NUM_JACKPOT 6
class Lottery;
randc int six_jackpot_nums[`NUM_JACKPOT];
constraint rand_jackpot {
foreach (six_jackpot_nums[i])
six_jackpot_nums[i] inside {[1:49]};
}
endclass
class Pick;
randc int six_jackpot_nums[`NUM_JACKPOT];
randc int jackpot_result [`NUM_JACKPOT];
int award_2nd_hi = `NUM_JACKPOT -1;
function pre_randomize();
Lottery l = new();
l.randomize();
$display("Jackpot bingo:");
for (int i=0; i<`NUM_JACKPOT; i++) begin
six_jackpot_nums[i] = l.six_jackpot_nums[i];
$write("%0d ", l.six_jackpot_nums[i]);
end
endfunction
constraint pick_jackpot{
foreach (jackpot_result[i])
jackpot_result[i] inside {[1:49]};
award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5]));
}
function int match(int v);
int tmp[$];
tmp = six_jackpot_nums.find(x) with (x == v);
if(tmp.size != 0) return 1;
return 0;
endfunction
endclass
以目前的状态,我可以成功创建六号头奖。然而,当我创建第二高的数字对时,我遇到了冲突。请指教
结果:
xmsim: *W,RNDOCS: These constraints contribute to the set of conflicting constraints:
award_2nd_hi == (match(jackpot_result[0])+match(jackpot_result[1])+match(jackpot_result[2])+match(jackpot_result[3])+match(jackpot_result[4])+match(jackpot_result[5])); (./design.sv,31)
xmsim: *W,RNDOCS: These variables contribute to the set of conflicting constraints:
Var_Name Type Status Current_Value Source
-----------------------------------------------------------------------------------------------------
award_2nd_hi (S32) STATE VAR 5 (0x5) ./design.sv ; line 16
jackpot_result[0] (S32) SOLVED EARLY 32 (0x20) ./design.sv ; line 15
jackpot_result[1] (S32) SOLVED EARLY 47 (0x2f) ./design.sv ; line 15
jackpot_result[2] (S32) SOLVED EARLY 21 (0x15) ./design.sv ; line 15
jackpot_result[3] (S32) SOLVED EARLY 40 (0x28) ./design.sv ; line 15
jackpot_result[4] (S32) SOLVED EARLY 1 (0x1) ./design.sv ; line 15
jackpot_result[5] (S32) SOLVED EARLY 27 (0x1b) ./design.sv ; line 15
match( .v( jackpot_result[0] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[1] ) ) (S32) SOLVED EARLY 1 (0x1) ./design.sv ; line 31
match( .v( jackpot_result[2] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[3] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[4] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
match( .v( jackpot_result[5] ) ) (S32) SOLVED EARLY 0 (0x0) ./design.sv ; line 31
Jackpot bingo:
31 49 43 24 47 8
Picked result:
0 0 0 0 0 0
这是一种更简单的方法,可以避免所有警告(以及其他模拟器上的错误)。随机生成一组 6 个获胜者。此外,随机选择一个获胜者,用失败的号码代替。使用 post_randomize
,创建一组失败者,然后随机选择其中一个并替换其中一个获胜者。
`define NUM_JACKPOT 6
class Lottery;
rand int six_jackpot_nums[`NUM_JACKPOT];
int jackpot_result [`NUM_JACKPOT];
int losers [$];
rand int unsigned idx;
function void post_randomize;
for (int i=1; i<50; i++) begin
if (!(i inside {six_jackpot_nums})) losers.push_back(i);
end
losers.shuffle();
for (int i=0; i<`NUM_JACKPOT; i++) begin
jackpot_result[i] = (i == idx) ? losers[0] : six_jackpot_nums[i];
end
endfunction
constraint rand_jackpot {
unique {six_jackpot_nums};
foreach (six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
idx inside {[1:`NUM_JACKPOT]};
}
endclass
module tb;
Lottery lot;
initial begin
lot = new();
void'(lot.randomize());
$display("\nPicked result:");
for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.six_jackpot_nums[i]);
$display("\nJackpot bingo:");
for (int i=0; i<`NUM_JACKPOT; i++) $write("%0d ", lot.jackpot_result [i]);
$display;
end
endmodule
示例输出:
Picked result:
48 4 46 3 17 16
Jackpot bingo:
48 4 21 3 17 16
这里,46被21代替了。
要解决 randc
问题,请使用 unique
约束关键字。
声明 randc 不能保证数组元素在单一随机化中是唯一的。所以我添加了一个约束 unique_cons 来解决这个问题。
`define NUM_JACKPOT 6
class Lottery;
rand int six_jackpot_nums[`NUM_JACKPOT];
rand int jackpot_result [`NUM_JACKPOT];
rand int missed;
constraint unique_cons {
foreach (six_jackpot_nums[i])
foreach(six_jackpot_nums[j])
if(i!=j) six_jackpot_nums[i]!=six_jackpot_nums[j];
}
constraint valid_cons {
foreach (six_jackpot_nums[i]){
six_jackpot_nums[i] inside {[1:49]};
jackpot_result[i] inside {[1:49]};
}
}
constraint missed_cons {
missed inside {[0:`NUM_JACKPOT-1]} ;
}
constraint rand_jackpot {
foreach (six_jackpot_nums[i])
if(i==missed)
~(jackpot_result[i] inside {six_jackpot_nums});
else
jackpot_result[i] == six_jackpot_nums[i];
}
endclass
结果:
Jackpot bingo:
30 44 12 37 1 22
Picked result:
30 44 12 37 1 9
Jackpot bingo:
40 12 20 46 8 2
Picked result:
40 12 20 5 8 2
Jackpot bingo:
29 23 13 41 48 28
Picked result:
29 39 13 41 48 28
Jackpot bingo:
8 14 35 19 28 39
Picked result:
8 20 35 19 28 39
第一个答案的好电话,unique 约束关键字已在 systemverilog-2012 中启用。
您应该尽可能寻找避免 pre/post_randomize()
的解决方案。这使得在一次解决所有约束和随机变量时更容易覆盖或添加更多约束。
parameter int JACKPOT_NUM = 6;
class Lottery;
rand int six_jackpot_nums[JACKPOT_NUM];
rand int pick_result_nums[JACKPOT_NUM];
constraint jack_rand {
unique {six_jackpot_nums};
foreach(six_jackpot_nums[i]) six_jackpot_nums[i] inside {[1:49]};
unique {pick_result_nums};
foreach(pick_result_nums[i]) pick_result_nums[i] inside {[1:49]};
}
constraint pick5 {
pick_result_nums.sum() with (int'(item == six_jackpot_nums[item.index])) == 5;
}
endclass
module tb;
initial begin
static Lottery l = new();
repeat(3) begin
assert(l.randomize());
$display("\nBingo result:");
foreach(l.six_jackpot_nums[i])
$write("%0d ", l.six_jackpot_nums[i]);
$display("\nPicked result:");
foreach(l.six_jackpot_nums[i])
$write("%0d ", l.pick_result_nums[i]);
$write("\n");
end
end
endmodule
这样做可以让您添加更多限制条件,例如“不匹配的所选号码必须比中奖号码大一”。这当然使 49 不会被选为错过的累积奖金号码,但它也不会错过任何两个连续累积奖金号码中的第一个。