best way to sum list items in e/Specman - specman

I created a list of structs and I like to sum the value of a field in each struct that satisfied a specific condition.
For example:
struct packet {
val:int;
cond:bool;
};
l:list of packet;
When I write the following:
keep l.all(it.cond).sum(it.val) == 1000;
I get an error: GEN_NO_GENERATABLE_NOTIF.
When I define a result variable:
sum_val : int;
keep sum_val == 100;
and change the constraint to:
keep l.all(it.cond).sum(it.val) == sum_val;
I get a contradiction!
How do I make it work?

You should use the list pseudo method "sum" and the ternary operation:
keep l.sum(it.cond ? It.val : 0) == 1000

From the question it seems you want to sum some elements in existing list, not generate a new one. In this case, use simply :
var sum : int = l.all(it.cond).sum(it.val);

Related

GEN_NO_GENERATABLE_NOTIF

I want to choose index from list, so the element[index] complies my condition.
MyList[index].num==0
I tried the code bellow:
gen DescIdx2Choose keeping {
it < MyList.size();
MyList[it].num==0;//I tried a few way of read_only
};
How can I do it without using all_indices?
Thanks
Since you generating DescIdx2Choose then MyList will be input to the problem.
Therefore,
If seeking for the first index (if exists) then using random generation isn't required. Use the procedural code "first_index" as user3467290 suggested which is much more efficient:
var fidx := MyList.first_index(.num == 0);
if ( fidx != UNDEF ) {
DescIdx2Choose = fidx;
} else {
// error handling
};
If there are multiple indices and it is required to choose a random one, the most efficient way would be using "all_indices" as Thorsten suggested:
gen DescIdx2Choose keeping {
it in read_only( MyList.all_indices(.num == 0) );
};
The reason is the random generator doesn't need to read all possible values of "MyList.num" only a shorter list of valid indices.
This should do it, but MyList must fulfill the condition otherwise you get a contradiction. Pseudo-method first_index() is not bi-directional which is what we need here.
gen DescIdx2Choose keeping {
MyList.first_index(.num == 0) == it;
};
Maybe i missed something in the question, but If you always want the index of the first element that its num == 0, then why use constraints? can assign DescIdx2Choose == MyList.first_index(.num == 0).
To ensure that there is at least one such element, can constrain MyList.has(.num == 0).
Do you have additional constraints on DescIdx2Choose ?

Passing hashset itself as parameter for reduce in swift

Given a hashset h = [1,2,3,4,5] for example, the purpose is to count the number of unique element i such that h.contains(i+1).
I can write down swift code using reduce() as
h.reduce(0,{h.contains($1+1) ? $0 + 1 : $0})
But what if h is an array containing duplicates instead of a hashset? I first need to convert it into hashset and then using the above expression:
Set(h).reduce(0,{Set(h).contains($1+1) ? $0 + 1 : $0})
But in this way we calculated Set(h).count + 1 times of Set(h) as pointed out by #carpsen90, is there any way to write the code like
Set(h).reduce(0,{self.contains($1+1) ? $0 + 1 : $0})
without using a temporary variable to store Set(h)?
Every time you call Set(h) a new set is calculated, so in your example Set(h).reduce(0,{Set(h).contains($1+1) ? $0 + 1 : $0}) , Set(h) will be calculated h.count + 1 times. Having a variable let set = Set(h) is the way to go here :
let set = Set(h)
let result = set.reduce(0) {set.contains($1+1) ? $0 + 1 : $0}
He is an alternative way of getting the desired result :
Let's create a dictionary that indicates wether a number has appeared in h:
var dict = [Int: Bool].init(minimumCapacity: h.count)
for x in h {
if dict[x] == nil {
dict[x] = true
}
}
And then, for each h element, check that its successor appears in the dictionary :
var count = 0
for entry in dict {
if dict[entry.key + 1] == true {
count += 1
}
}
And you could check the result :
print(count) //4
The problem here is that your array might contain duplicates and to filter the duplicates the easiest way is to convert it into the Set. And the correct way to do that is to save the set in a new variable hence it is unavoidable.
Though you can still use the reduce method without converting your array into a set like this:
var tempH = [Int]()
let c = h.reduce(0) { (result, item) in
if (!tempH.contains(item)) {
tempH.append(item)
return h.contains(item+1) ? (result + 1) : result
}
else {return result}
}
But, as you can notice in above code, we have to use a temporary array to track our duplicates. Hence an extra variable seems unavoidable here. Though no Sets are being used in above code.

List of list generation

simple question :
for simplicity : struct contains only one item of type bool :
struct dummy_s {
is_high : bool;
};
I've a matrix of struct :
matrix : list of list of dummy_s;
My intention is to have at least one list which contain number of structs which have more than 1 'is_high == TRUE'.
Whats wrong with the code i wrote :
keep matrix.has(it.count(it.is_high) > 1);
List-pseudo-method inside list-pseudo-method is currently considered an input for the random generator - meaning, non generative.
a generative model can be:
matrix : list of list of dummy_s;
idx : uint;
keep idx < value(matrix.size());
keep for each in matrix {
idx == index => it.count(it.is_high) > 1;
};

a good way to constrain sum of different instances

I have a struct (mystruct_s for example) under which there are several same type structs (packet_s for example) in different hierarchies.
struct packet_s {
size:uint;
active:bool;
};
struct mystruct_s {
// packet struct paths:
// p
// q.p
// w.p
};
I would like to generate an instance of mystruct_s and enforce that the sum of the sizes of all active packets would be less than 1K.
var s : mystruct_s;
gen s keeping {
// it.p.size (if it.p.active) + it.q.p.size (if it.q.p.active) + it.w.p.size (if it.w.p.active) < 1024 ;
};
Is there a simple way to approach this problem?
The straightforward solution would be using ternary and plus to sum the sizes if active :
var s : mystruct_s;
gen s keeping {
(it.p.active ? it.p.size : 0) + (it.q.p.active ? it.q.p.size : 0) + (it.w.p.active ? it.w.p.size : 0) < 1024 ;
};
If you using Specman 14.1 (or above) you can use generative literal list and sum to write the following constraint:
var s : mystruct_s;
gen s keeping {
{it.p; it.q.p; it.w.p}.sum(it.active ? it.size : 0)) < 1024 ;
};
Using generative literal list will also give you better distribution on the sizes.
If you using Specman 14.2 (or above) you can use conditional sum instead of sum with ternary:
var s : mystruct_s;
gen s keeping {
{it.p; it.q.p; it.w.p}.sum(it.size, it.active) < 1024 ;
};
Replace all instances of packet_s with a single list.
Then use list pseudo method .sum constraint
Try (not sure if this will work):
extend my_struct {
keep {p.sizep.active.as_a(bit),w.p.sizew.p.active.as_a(bit),...}.sum(it) < 1024;
}
Keep %{mystruct.p.size, mystruct.q.p, ...}.count(it) < 1K

How do I declare a list of fixed length in specman?

In E (specman) I want to declare variables that are lists, and I want to fix their lengths.
It's easy to do for a member of a struct:
thread[2] : list of thread_t;
while for a "regular" variable in a function the above doesn't work, and I have to do something like:
var warned : list of bool;
gen warned keeping {
it.size() == 5;
};
Is there a better way to declare a list of fixed size?
A hard keep like you have is only going to fix the size at initialization but elements could still be added or dropped later, are you trying to guard against this condition? The only way I can think of to guarantee that elements aren't added or dropped later is emitting an event synced on the size != the predetermined amount:
event list_size_changed is true (wanted.size() != 5) #clk;
The only other thing that I can offer is a bit of syntactic sugar for the hard keep:
var warned : list of bool;
keep warned.size() == 5;
I know nothing of specman, but a fixed sized list is an array, so that might point you somewhere.