a good way to constrain sum of different instances - specman

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

Related

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.

How to remove all array items except at indexes at multiples of x - Swift

I have an array of coordinates (965 in total). I want to use these coordinates in Google Roads API however the limit is 100.
I have a function that determines how many items in the array and then gets the value to use.
round(Double(userCoordinatesHardCoded.count / 100))
produces 9.
I would like to remove ALL items that are not at indexes that are multiples of, in this case, 9. So in theory I will only ever have no more than 100 items in the array.
If possible, I would like to keep the first and last array item.
I know this has already been answered, but this is a great use case for using the filter function built into Swift:
let newCoordinates = oldCoordinates.filter { coord in
return (coord % 9 != 0)
}
If space is not a problem, you can create another array with the desired multiples.
var oldCoordinates // Imagine it having all those elements
var newCoordinates : GoogleCoordinates = [] // This one will have new ones
newCoordinates.append(oldCoordinates[0])
var x = 1
for (x; x < oldCoordinates.count ; x++ ) {
if (x % 5 == 0) {
newCoordinates.append(oldCoordinates[x])
}
}
if (x != (oldCoordinates.count - 1)) {
newCoordinates.append(oldCoordinates[oldCoordinates.count - 1])
}

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;
};

best way to sum list items in e/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);

How to use instances of a module with instances' index?

For example,
module MM;
MM mm[128]();
I want to get mm[i].signle1,i from 0 to 120.
but I cannot use "for", and I do not want to write 120 statments.
what can I do?
You can create a list of ports and you can use a for loop:
signals : list of simple_port of bit is instance;
keep signals.size() == 128;
keep for each (s) in signals {
s.hdl_path() == append("mm[",dec(i),"].signal1");
};