List of list generation - specman

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

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.

Randomize order of a MongoDB query in Go

Here is my query :
c := session.DB("searchV").C("video")
var results []BadVideo
err5 := c.Find(nil).All(&results)
fmt.Println("request done")
if err5 != nil {
panic(err5)
}
var i = 0
for _,badvideo := range results {
}
I would like to randomize the order of browsing the items of the query for making operation on each item of the request ...
So each time I run it, I browse it in a different order.
Manual shuffling
Here's a simple shuffle algorithm, which shuffles (randomizes) a []BadVido slice:
func shuffle(r []BadVideo) {
for i := len(r) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
r[i], r[j] = r[j], r[i]
}
}
So after you loaded your results, simply call shuffle(results) on it.
For testing, I will use a simple BadVideo type:
type BadVideo struct {
Name string
}
func main() {
rand.Seed(time.Now().UnixNano())
results := []BadVideo{{"a"}, {"b"}, {"c"}, {"d"}, {"e"}}
shuffle(results)
fmt.Println(results)
}
Output (try it on the Go Playground):
[{c} {d} {b} {e} {a}]
How it works:
To shuffle a slice, the shuffle() function randomly selects one element from the slice for each index. It does it like iterating over all elements downward, and selects a random element from the remaining slice (including index of the element we're currently selecting, because random orders also include ones where an element "stays in place"), and using a random index to swaps the element with the chosen random one. The loop goes until i > 0 (and not until i >=0), because if only 1 element left, no need to swap it with itself.
Using rand.Perm()
Another variant of shuffle() could take advantage of rand.Perm() which returns a slice containing shuffled numbers. We can use these random numbers to tell how to reorder the results:
func shuffle(r []BadVideo) {
r2 := append([]BadVideo(nil), r...)
for i, j := range rand.Perm(len(r)) {
r[i] = r2[j]
}
}
Try this variant on the Go Playground.
One thing to note here: before we do the reordering, we have to save the original slice (make a copy of it), so we can select the original elements specified by random indices when writing the results in the slice. I created a copy by appending the complete slice to a nil slice.

Iterate and save cursor - MongoDB

I have this array in MongoDB:
I want to iterate and make queries on it:
> for(var i=0; i < AllegriTeams.length; i++) {a[i]=db.team.find({
_id:AllegriTeams[i].team_id}, {_id:0, official_name:1})}
The array a, at the end of for cycle, contains just the first two official names. I lose the last official_name.
Your loop looks correct and it is not clear why you would not receive three items in your array a.
Check that your variable AllegriTeams has three elements.
> AllegriTeams.length
3
I mimicked your setup and I received the results you expected where a has three elements. Here's what I did:
// 1. Log into mongo and use the "test" database, for example
> use test
// 2. Create data
> db.team.insert({"_id": "Juv.26", "official_name":"Juv.26.xxx”})
WriteResult({ "nInserted" : 1 })
> db.team.insert({"_id": "Mil.74", "official_name":"Mil.74.xxx”})
WriteResult({ "nInserted" : 1 })
> db.team.insert({"_id": "Cag.00", "official_name":"Cag.00.xxx”})
WriteResult({ "nInserted" : 1 })
// 3. Create the AllegriTeams variable
> var AllegriTeams = [ { "team_id":"Juv.26"}, {"team_id":"Mil.74"}, {"team_id":"Cag.00"}]
// 4. Create the "a" array
> var a = []
// 5. Run the for loop. Consider using "findOne" instead of "find".
> for (var i=0; i < AllegriTeams.length; i++) { a[i]=db.team.find({ _id:AllegriTeams[i].team_id}, {_id:0, official_name:1})}
{ "official_name" : "Cag.00.xxx" }
// 6. Get length of "a"
> a.length
3
As an aside, take note that the find() function will return a cursor. Therefore, the values stored in your a array will be the cursor values. Consider using the findOne() function since it returns a document.
Again, check that your AllegriTeam variable has three array elements.

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

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