How to check two Time durations overlaps in Alloy - alloy

I have following signatures and predicate for checking two Time duration overlaps
sig Time{}
sig Duration{
startTime : one Time,
endTime : one Time
}
pred isTimeOverlap[a, b : Duration] {
//
}
I want to implement following logic in Alloy(as predicate isTimeOverlap). Is there any specific way to handle Time in Alloy
function Boolean isTimeOverlapp(Time $time1start, Time $time1end, Time $time2start, Time $time2end) {
if(($time1start <= $time2end) && ($time2start <= $time1end)) {
return TRUE;
} else {
return FALSE;
}
}

I think alloy prefers a relational situation in this case. Note that Time is an (ordered) set. So between 2 Time atoms there are a number of other Time atoms. I.e. a range is a set of Time. Overlap is then a simple overlap in their set values. I.e. if they have any Time in common. Since each ordered atom has a nexts function you can easily calculate the members of a range.
open util/ordering[Time]
sig Time {}
let range[s,e] = (s + s.nexts) - e.nexts // inclusive bounds i.e. [s,e]
let overlap[s1,e1,s2,e2] = some (range[s1,e1] & range[s2,e2])
check {
// [t0,t0] ∩ [t0,tn]
overlap[ first, first, first, last ]
// [t0,t1] ∩ [t1,tn]
overlap[ first, first.next, first.next, last ]
// [t0,t1] ∩ [t0,tn]
overlap[ first, first.next, first, last ]
// [t0,t1] ∩ [t0,t1]
overlap[ first, first.next, first, first.next ]
// not ( [t1,t0] ∩ [t0,t1] )
not overlap[ first.next, first, first, last ]
// not ( [t0,t1] ∩ [t2,tn] )
not overlap[ first, first.next, first.next.next, last ]
// reflexive
all t1, t2, t3, t4 : Time | overlap[t1,t2,t3,t4] <=> overlap[t3,t4,t1,t2]
} for 10

Related

How can I switch from operator to another operator?

I'm making a program that can understands human words, and so far it's going great.
My current standpoint is understanding math equations. You can add, subtract, multiply and divide very easily with as many numbers as you'd like, but I'm wondering how I can do addition then multiply the result, like this:
const source = require("./source.js")
var main = source.interpret(
"add 4 and 4 multiply by 4",
)
source.output(main)
And it should output:
64
Yes I know that there is an easier way of doing this math equation, however in any calculator of any sort you should be able to this kind of switching in any context.
How can I accomplish this?
Here is the full source code;
index.js:
const source = require("./source.js")
var main = source.interpret(
"add 4 and 4 together then multiply the result by 4",
)
source.output(main)
source.js:
function output(main) {
console.log(main)
}
function interpret(str) {
const dl = str.split(' ');
const operator = dl.shift(x => x.includes("add", "subtract", "multiply", "divide"))
const numbers = dl.filter(x => Number(x))
switch (operator) {
case "add":
return numbers.reduce((a, b) => Number(a) + Number(b));
case "subtract":
return numbers.reduce((a, b) => Number(a) - Number(b));
case "multiply":
return numbers.reduce((a, b) => Number(a) * Number(b));
case "divide":
return numbers.reduce((a, b) => Number(a) / Number(b));
}
}
module.exports = {interpret, output}
The main problem with your interpret function is that after finding a single operator, it will perform that operation on all numbers and immediately return. We can’t simply reduce all the numbers using the first operation we find, because it’s possible that some numbers are related to other operations! In the expression add 2 and 2 multiply by 3, the 3 is related to the multiply operation!
This means that we can't process the entire input like that. An alternative is to iterate over the input, and depending on the operator we find, we perform the related action.
To simplify, let's consider that there's only the add operation. What are we expecting next? It could be [number] and [number], but also, it can be by [number]. The first one just adds the two numbers, but in the second, it should add the new number to the last operation.
A side note: your shift and filter functions are parsing the input, and the switch case is interpreting the parsed structure. Your “human language” is actually a programming language! add 2 and 2 is analogous to 2 + 2 in JavaScript, just different. With that, I will introduce you to some programming language theory terms, it can be easier to search for more help if you deep dive in the topic.
Considering the last paragraph, let's refactor interpret:
// from https://stackoverflow.com/questions/175739/how-can-i-check-if-a-string-is-a-valid-number
function isNumeric(str) {
if (typeof str != "string") return false
return !isNaN(str) && !isNaN(parseFloat(str))
}
function interpret(input) {
const tokens = input.split(' ') // in fancy programming language terms,
// this is a lexical analysis step
// note that we are not supporting things like
// double spaces, something to think about!
let state = 0 // we are keeping the results from our operation here
for (i = 0; i < tokens.length; i++) {
const t = tokens[i] // to keep things shorter
switch (t) {
case "add": // remember: there's two possible uses of this operator
const next = tokens[i + 1]
if (next == "by") {
// we should add the next token (hopefully a number!) to the state
state += parseFloat(tokens[i + 2])
i += 2 // very important! the two tokens we read should be skipped
// by the loop. they were "consumed".
continue // stop processing. we are done with this operation
}
if (isNumeric(next)) {
const a = tokens[i + 2] // this should be the "and"
if (a != "and") {
throw new Error(`expected "and" token, got: ${a}`)
}
const b = parseFloat(tokens[i + 3])
state = parseFloat(next) + b
i += 3 // in this case, we are consuming more tokens
continue
}
throw new Error(`unexpected token: ${next}`)
}
}
return state
}
const input = `add 2 and 2 add by 2 add by 5`
console.log(interpret(input))
There's a lot to improve from this code, but hopefully, you can get an idea or two. One thing to note is that all your operations are "binary operations": they always take two operands. So all that checking and extracting depending if it's by [number] or a [number] and [number] expression is not specific to add, but all operations. There's many ways to write this, you could have a binary_op function, I will go for possibly the least maintainable option:
// from https://stackoverflow.com/questions/175739/how-can-i-check-if-a-string-is-a-valid-number
function isNumeric(str) {
if (typeof str != "string") return false
return !isNaN(str) && !isNaN(parseFloat(str))
}
function isOperand(token) {
const ops = ["add", "multiply"]
if (ops.includes(token)) {
return true
}
return false
}
function interpret(input) {
const tokens = input.split(' ') // in fancy programming language terms,
// this is a lexical analysis step
// note that we are not supporting things like
// double spaces, something to think about!
let state = 0 // we are keeping the results from our operation here
for (i = 0; i < tokens.length; i++) {
const t = tokens[i] // to keep things shorter
if (!isOperand(t)) {
throw new Error(`expected operand token, got: ${t}`)
}
// all operators are binary, so these variables will hold the operands
// they may be two numbers, or a number and the internal state
let a, b;
const next = tokens[i + 1]
if (next == "by") {
// we should add the next token (hopefully a number!) to the state
a = state
b = parseFloat(tokens[i + 2])
i += 2 // very important! the two tokens we read should be skipped
// by the loop. they were "consumed".
}
else if (isNumeric(next)) {
const and = tokens[i + 2] // this should be the "and"
if (and != "and") {
throw new Error(`expected "and" token, got: ${and}`)
}
a = parseFloat(next)
b = parseFloat(tokens[i + 3])
i += 3 // in this case, we are consuming more tokens
} else {
throw new Error(`unexpected token: ${next}`)
}
switch (t) {
case "add":
state = a + b
break;
case "multiply":
state = a * b
}
}
return state
}
const input = `add 2 and 2 add by 1 multiply by 5`
console.log(interpret(input)) // should log 25
There's much more to explore. We are writing a "single-pass" interpreter, where the parsing and the interpreting are tied together. You can split these two, and have a parsing function that turns the input into a structure that you can then interpret. Another point is precedence, we are applying the operation in the order they appear in the expression, but in math, multiplication should be done first than addition. All of these problems are programming language problems.
If you are interested, I deeply recommend the book http://craftinginterpreters.com/ for a gentle introduction on writing programming languages, it will definitely help in your endeavor.

Predicate not consistent

I have to realize an application which permits to reserve a seat in a store. There are no sintax error, but I don't understand why terminal reply me "predicate not consistent". Can u help me?
This is my code:
open util/integer
sig Email{}
sig CF{}
sig Time{
hour: one Int,
minute:one Int,
second: one Int
}
abstract sig RegisteredUser{
email: one Email
}
sig User extends RegisteredUser{
cf: one CF
}
sig SM extends RegisteredUser{
cf: one CF,
store: one Store
}
sig Location{}
sig Date{}
abstract sig Status {}
//only one of this can be true
one sig Waiting extends Status {}
one sig Expired extends Status{}
one sig Pending extends Status{}
sig Ticket{
owner:one User,
date: one Date,
time: one Time,
status : one Status,
}
sig Visit{
owner:one User,
date: one Date,
time: one Time,
duration:one Time,
status : one Status,
products: some Product,
category: some Category,
}
//tickets are assumed with a default duration time of 15 min and entrance one for time, so 4*8=32 visit per day
sig TicketQueue {
max_visit:one Int,
ticket: some Ticket,
manager: one SM
}
sig VisitQueue{
category: some Category,
visit: some Visit,
manager: one SM
}
sig Store{
max_simultaneous: one Int,
location: one Location,
visitqueue: one VisitQueue,
ticketqueue: one TicketQueue,
product_category: some Category
}
sig Category{
simultaneous_seats: one Int,
}
sig Product{
category: one Category
}
// Constraints
// Registration data for the system are unique(Unique username and Fiscal Code)
fact registrationDataUniqueness {
no disjoint u1, u2: RegisteredUser | u1.email = u2.email
no disjoint u1,u2: User | u1.cf = u2.cf
no disjoint s1,s2: SM | s1.cf = s2.cf
no disjoint s:SM, u:User | s.cf=u.cf
}
//Ticket and Visit can have only one of status' values defined before
fact requestConsistency {
all s: Status | (s = Waiting && s != Expired && s !=Pending ) || (s != Waiting && s = Expired && s != Pending) || (s !=Waiting && s != Expired && s = Pending)
}
//SM can manage only one Store
fact StoreUniqueness{
no disjoint s1,s2: SM |s1.store=s2.store
}
// the same ticket or visit cannot be of two or more different user
fact UserUniqueness{
no disjoint t1,t2: Ticket | t1.owner=t2.owner
no disjoint v1,v2: Visit | v1.owner=v2.owner
}
//different products can not be of the same category
fact CategoryUniqueness{
no disjoint p1,p2: Product | p1.category=p2.category
}
//different stores can't have the same ticket or visit queue
fact QueueUniqueness{
no disjoint s1,s2: Store | s1.ticketqueue=s2.ticketqueue
no disjoint s1,s2: Store | s1.visitqueue=s2.visitqueue
}
//different tickets cannot have the same time
fact TimeUniqueness{
no disjoint t1,t2: Ticket | t1.time = t2.time
}
//for semplicity,in the visit/ticket queue, we consider "active" only visit/ticket with Waiting status
fact StatusQueue{
all tq:TicketQueue | tq.ticket.status=Waiting
all vq:VisitQueue | vq.visit.status=Waiting
}
//one ticket/visit can not belong to two or more different queue
fact ReservationUniqueness{
no disjoint tq1,tq2:TicketQueue | tq1.ticket=tq2.ticket
no disjoint vq1,vq2:VisitQueue | vq1.visit=vq2.visit
}
//SM is unique for a specific store, and its related ticket/visit queue
fact SMUniqueness{
no disjoint s1,s2: Store | s1.ticketqueue.manager=s2.ticketqueue.manager
and s1.visitqueue.manager=s2.visitqueue.manager
and s1.ticketqueue.manager=s2.visitqueue.manager
and s1.visitqueue.manager=s2.ticketqueue.manager
}
//different tickets/visits associated with the same user have different time
fact UniqueTimeUser {
all u: User, t1, t2: Ticket, v1,v2:Visit | ((u in t1.owner) and (u in t2.owner) and (u in v1.owner) and (u in v2.owner)
and (t1 != t2) and (v1 !=v2))
implies (t1.time != t2.time)
and (v1.time != v2.time)
}
//different ticket and visit associated with the same user have different time
fact UniqueTimeUser2 {
all u: User, t: Ticket, v:Visit | ((u in t.owner) and (u in v.owner) )
implies (v.time != t.time)
}
//Maximum number of visit with the same time for category
fact MaxTime{
all v:Visit, c: Category |(( c in v.category)) implies #v.time< c.simultaneous_seats
}
//Considering meaningfull integer value
fact PossibleValues{
all c: Category | c.simultaneous_seats>1 and c.simultaneous_seats<5
all s: Store | s.max_simultaneous >0 and s.max_simultaneous<50
all t: Ticket | t.time.hour>7 and t.time.hour<21 and ((t.time.minute=15) || (t.time.minute=30) || (t.time.minute=45)) and t.time.second=0
all v: Visit | v.time.hour>7 and v.time.hour<21 and ((v.time.minute=15) || (v.time.minute=30) || (v.time.minute=45)) and v.time.second=0 and v.duration.hour=0 and v.duration.minute>0 and v.duration.minute=<30 and v.duration.second=0
all tq: TicketQueue | tq.max_visit=32
}
pred addTicket[ t :Ticket,ti,ti':Time, tq, tq':TicketQueue]{
//precondition
ti' not in Ticket.time
#tq.ticket< tq.max_visit //seats available
//postconditions
tq'.manager= tq.manager
tq'.ticket= tq.ticket+t
t in tq'.ticket
#tq'.ticket< tq.max_visit
all t': Ticket | t' in tq.ticket implies t' in tq'.ticket
}
pred show{
#User = 4
#Store = 2
#SM = 2
#Category = 3
#TicketQueue = 2
#VisitQueue= 2
#Category = 5
some v, v': Visit | v.time != v'.time
#Ticket = 5
#Visit=5
}
run show for 4
This is the complete response of Alloy terminal:
Executing "Run show for 4"
Solver=sat4j Bitwidth=4 MaxSeq=4 SkolemDepth=1 Symmetry=20
15098 vars. 840 primary vars. 17697 clauses. 28ms.
No instance found. Predicate may be inconsistent. 1ms.
Have you run unsat core (using the MiniSAT with Unsat Core solver)? That might give you a hint. Another thought: I would simplify the model first and then only add features as you need them. I'm not sure that you really need to split the times into hours, minutes and seconds. That adds a lot of solver complexity, perhaps needlessly.
General observations:
Some inconsistences in your show predicate:
#Category = 3
#Category = 5
Your scope is definitely too small. You can't expect 5 Visit elements if you have a general scope of 4.
I'd rewrite your show predicate and run command as follows:
pred show{
some v, v': Visit | v.time != v'.time
}
run show for 10 but 7 Int, exactly 4 User, exactly 2 Store, exactly 2 SM, exactly 3 Category, exactly 2 TicketQueue, exactly 2 VisitQueue, exactly 5 Ticket, exactly 5 Visit
Notice the 7 Int.
It means that your model will contain int type atoms that represent all the integers you can express with a bitwidth of 7 (interval is [-64,63]).
As Daniel wrote, i'd also advise to stay as abstract as possible when you model in Alloy and thus to prefer concepts over quantitative values.
I concur with the previous advice of simplifying and would add to use check statements to test as you go. I'm not an expert with Alloy, so I take it slow and test early and often.
One thing that sticks out to me immediately is that your "show" predicate seems to be specifying multiplicities for some signatures that are greater than those allowed by the run statement ("for 4"). I've never specified multiplicity in a predicate that way, so I don't know how Alloy handles that. Offhand, those seem like contradictory constraints.
Also, I figured this out the hard way, but Alloy counts instances (atoms) of extended signatures as instances (atoms) of the parent(s). So, be aware of that.

Can I write an object that behaves like a hash?

In Perl there is tie. Python supports various protocols so that objects can behave like i.e. a dictionary. Is there something similar in Raku?
I.e. Can I define an object that behaves like a Hash? That is: can I write $myobject<key> to end up in a routine that I can specify myself?
Perl has the Hash feature baked into the language.
So to extend it so that an object behaves like a Hash you needed to tell the runtime to do something different.
That is not the case for Raku.
A Hash in Raku is just another object.
The Hash indexing operation is just another operator that can be overloaded the same way you can overload other operators.
So you can create your own object that has the same features as a Hash, or even just inherit from it.
class Foo is Hash {
}
class Bar does Associative {
# delegate method calls to a Hash object
has %!hash handles Hash;
}
The reason to have does Associative is so that you can use it as the type to back an associative variable. (Hash already does Associative so you would inherit that too.)
my %f is Foo;
my %b is Bar;
To find out which methods you can write to implement Hash indexing operations you could look at the methods that Hash implements.
Since we know that methods that automatically get called are uppercase, we only need to look at them.
Hash.^methods.map(*.name).grep(/^<:Lu + [-]>+$/)
# (STORE BIND-KEY WHICH AT-KEY ASSIGN-KEY DELETE-KEY
# DUMP BUILDALL ASSIGN-KEY EXISTS-KEY AT-KEY STORE ACCEPTS BUILDALL)
It should be fairly obvious that the methods ending with -KEY are the ones we would want to write. (The other ones are mostly just object artifacts.)
You currently don't have to write any of them to make your object type Associative.
If you don't write a particular method, that feature won't work.
class Point does Associative {
has Real ($.x, $.y);
multi method AT-KEY ( 'x' ){ $!x }
multi method AT-KEY ( 'y' ){ $!y }
multi method ASSIGN-KEY ( 'x', Real $new-value ){ $!x = $new-value }
multi method ASSIGN-KEY ( 'y', Real $new-value ){ $!y = $new-value }
multi method EXISTS-KEY ( 'x' --> True ){}
multi method EXISTS-KEY ( 'y' --> True ){}
multi method EXISTS-KEY ( Any --> False ){}
}
my %p is Point;
%p<x> = 1;
%p<y> = 2;
say %p.x; # 1
say %p.y; # 2
Note that above has a few limitations.
You can't assign to more than one attribute at a time.
%p< x y > = 1,2;
You can't assign the values in the declaration.
my %p is Point = 1,2;
my %p is Point = x => 1, y => 2;
In the multi-assignment, the method that gets called is AT-KEY. So to make it work those must be marked as raw or rw
class Point does Associative {
…
multi method AT-KEY ( 'x' ) is rw { $!x }
multi method AT-KEY ( 'y' ) is rw { $!y }
…
}
…
%p<x y> = 1,2;
That takes care of multi assignment, but that still leaves the initialization in the declaration.
If you declared an attribute as is required the only way to write it would be:
my %p := Point.new( x => 1, y => 2 );
If you didn't do that you could implement STORE.
class Point does Associative {
…
method STORE ( \list ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
That also makes it so that you can also assign to it later.
%p = x => 3, y => 4;
Which is possibly not what you wanted.
We can fix that though.
Just make it so that there has to be an :INITIALIZE argument.
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
($!x,$!y) = list.Hash<x y>
}
}
my %p is Point = x => 1, y => 2;
# %p = x => 3, y => 4; # ERROR
In the case of Point we might want to be able to declare it wit a list of two elements:
my %p is Point = 1,2;
Or by name:
my %p is Point = x => 1, y => 2;
To do that we can change how STORE works.
We'll just look at the first value in the list and check if it is Associative.
If it is we will assume all of the arguments are also Associative.
Otherwise we will assume that it is a list of two values, x and y.
class Point does Associative {
…
method STORE ( \list, :INITIALIZE($) is required ) {
if list.head ~~ Associative {
($!x,$!y) = list.Hash<x y>
} else {
($!x,$!y) = list
}
}
}
my %a is Point = x => 1, y => 2;
my %b is Point = 1,2;
In raku the syntactical <> seems to be an postcircumfix operator that can be overloaded via a multi method AT-KEY and EXISTS-KEY as described in https://docs.raku.org/language/subscripts#Methods_to_implement_for_associative_subscripting
Can I define a object that behaves like an hash? That is: if I write $myobject<key> I endup in a function that I can specify myself?
The short answer is. No, there is not in core Raku. But there is a module that makes it easy for you to do, having only to define 5 methods to create full functionality as a "real" Hash: Hash::Agnostic
The longer answer is: read the other answers to this question :-)

Lock Challenge in Alloy

I would like to solve the following lock challenge using Alloy.
My main issue is how to model the integers representing the digit keys.
I created a quick draft:
sig Digit, Position{}
sig Lock {
d: Digit one -> lone Position
}
run {} for exactly 1 Lock, exactly 3 Position, 10 Digit
In this context, could you please:
tell me if Alloy seems to you suitable to solve this kind of problem?
give me some pointers regarding the way I could model the key digits (without using Ints)?
Thank you.
My frame of this puzzle is:
enum Digit { N0,N1,N2,N3,N4,N5,N6,N7,N8,N9 }
one sig Code {a,b,c:Digit}
pred hint(h1,h2,h3:Digit, matched,wellPlaced:Int) {
matched = #(XXXX) // fix XXXX
wellPlaced = #(XXXX) // fix XXXX
}
fact {
hint[N6,N8,N2, 1,1]
hint[N6,N1,N4, 1,0]
hint[N2,N0,N6, 2,0]
hint[N7,N3,N8, 0,0]
hint[N7,N8,N0, 1,0]
}
run {}
A simple way to get started, you do not always need sig's. The solution found is probably not the intended solution but that is because the requirements are ambiguous, took a shortcut.
pred lock[ a,b,c : Int ] {
a=6 || b=8 || c= 2
a in 1+4 || b in 6+4 || c in 6+1
a in 0+6 || b in 2+6 || c in 2+0
a != 7 && b != 3 && c != 8
a = 7 || b=8 || c=0
}
run lock for 6 int
Look in the Text view for the answer.
upate we had a discussion on the Alloy list and I'd like to amend my solution with a more readable version:
let sq[a,b,c] = 0->a + 1->b + 2->c
let digit = { n : Int | n>=0 and n <10 }
fun correct[ lck : seq digit, a, b, c : digit ] : Int { # (Int.lck & (a+b+c)) }
fun wellPlaced[ lck : seq digit, a, b, c : digit ] : Int { # (lck & sq[a,b,c]) }
pred lock[ a, b, c : digit ] {
let lck = sq[a,b,c] {
1 = correct[ lck, 6,8,2] and 1 = wellPlaced[ lck, 6,8,2]
1 = correct[ lck, 6,1,4] and 0 = wellPlaced[ lck, 6,1,4]
2 = correct[ lck, 2,0,6] and 0 = wellPlaced[ lck, 2,0,6]
0 = correct[ lck, 7,3,8]
1 = correct[ lck, 7,8,0] and 0 = wellPlaced[ lck, 7,8,0]
}
}
run lock for 6 Int
When you think solve complete, let's examine whether the solution is generic.
Here is another lock.
If you can’t solve this in same form, your solution may not enough.
Hint1: (1,2,3) - Nothing is correct.
Hint2: (4,5,6) - Nothing is correct.
Hint3: (7,8,9) - One number is correct but wrong placed.
Hint4: (9,0,0) - All numbers are correct, with one well placed.
Yes, I think Alloy is suitable for this kind of problem.
Regarding digits, you don't need integers at all: in fact, it is a bit irrelevant for this particular purpose if they are digits or any set of 10 different identifiers (no arithmetic is performed with them). You can use singleton signatures to declare the digits, all extending signature Digit, which should be marked as abstract. Something like:
abstract sig Digit {}
one sig Zero, One, ..., Nine extends Digit {}
A similar strategy can be used to declare the three different positions of the lock. And btw since you have exactly one lock you can also declare Lock as singleton signature.
I like the Nomura solution on this page. I made a slight modification of the predicate and the fact to solve.
enum Digit { N0,N1,N2,N3,N4,N5,N6,N7,N8,N9 }
one sig Code {a,b,c: Digit}
pred hint(code: Code, d1,d2,d3: Digit, correct, wellPlaced:Int) {
correct = #((code.a + code.b + code.c)&(d1 + d2 + d3))
wellPlaced = #((0->code.a + 1->code.b + 2->code.c)&(0->d1 + 1->d2 + 2->d3))
}
fact {
some code: Code |
hint[code, N6,N8,N2, 1,1] and
hint[code, N6,N1,N4, 1,0] and
hint[code, N2,N0,N6, 2,0] and
hint[code, N7,N3,N8, 0,0] and
hint[code, N7,N8,N0, 1,0]
}
run {}
Update (2020-12-29):
The new puzzle presented by Nomura (https://stackoverflow.com/a/61022419/5005552) demonstrates a weakness in the original solution: it does not account for multiple uses of a digit within a code. A modification to the expression for "correct" fixes this. Intersect each guessed digit with the union of the digits from the passed code and sum them for the true cardinality. I encapsulated the matching in a function, which will return 0 or 1 for each digit.
enum Digit {N0,N1,N2,N3,N4,N5,N6,N7,N8,N9}
let sequence[a,b,c] = 0->a + 1->b + 2->c
one sig Code {c1, c2, c3: Digit}
fun match[code: Code, d: Digit]: Int { #((code.c1 + code.c2 + code.c3) & d) }
pred hint(code: Code, d1,d2,d3: Digit, correct, wellPlaced:Int) {
// The intersection of each guessed digit with the code (unordered) tells us
// whether any of the digits match each other and how many
correct = match[code,d1].plus[match[code,d2]].plus[match[code,d3]]
// The intersection of the sequences of digits (ordered) tells us whether
// any of the digits are correct AND in the right place in the sequence
wellPlaced = #(sequence[code.c1,code.c2,code.c3] & sequence[d1, d2, d3])
}
pred originalLock {
some code: Code |
hint[code, N6,N8,N2, 1,1] and
hint[code, N6,N1,N4, 1,0] and
hint[code, N2,N0,N6, 2,0] and
hint[code, N7,N3,N8, 0,0] and
hint[code, N7,N8,N0, 1,0]
}
pred newLock {
some code: Code |
hint[code, N1,N2,N3, 0,0] and
hint[code, N4,N5,N6, 0,0] and
hint[code, N7,N8,N9, 1,0] and
hint[code, N9,N0,N0, 3,1]
}
run originalLock
run newLock
run test {some code: Code | hint[code, N9,N0,N0, 3,1]}

How to write cover points for transition in systemverilog?

there is a N bit register in my RTL design and I want to check if testbench is covering following particular case-
000..0 -> 000..001 -> 000....011 -> 00...111 -> ...... -> 111....111
I'm not sure how to write cover group for above. I can see how transition coverage can be useful. As an example:
covergroup cg;
cover_point_y : coverpoint y {
bins tran_34 = (3=>4);
bins tran_56 = (5=>6);
}
However in my case, my register is paraterized (N bits: reg[(N-1):0]) and it's too big to write the full sequence manually. Can I write a generate or for loop to cover above sequence that I want to see?
It's not really clear to me which transitions you want to cover. I guess you want to cover that each value changed to every other value. What you need to keep in mind is that you can write multiple values on either side of the => operator. For example:
cover_point_y : coverpoint y {
bins transitions = ( 0, 1 => 0, 1 );
}
This will create bins for 0 => 0, 0 => 1, 1 => 0, 1 => 1. If I interpreted the BNF properly, according to the LRM, the values you put on either side of the => operator are of type covergroup_value_range, meaning that any value range syntax for coverpoints should be accepted. This means the following should also be legal:
cover_point_y : coverpoint y {
bins transitions = ( [0 : 2^N - 1] => [0 : 2^N - 1] );
}
This should create transition bins from every value to every other value. You're at the mercy of tool support here. This doesn't work in my simulator, for example, but it might work in others.
If you want to exclude certain transitions (for example, 0 => 0, 1 => 1, etc.) this won't help you anyway, because the syntax to specify transition bins just isn't expressive enough...
Don't fret, there are ways to do it. Going back to basics, transition coverage is basically a form of cross coverage between the current value and the past value. Cross coverage allows much more diverse ways of specifying bins. You need to track the previous value of the variable you're covering. The thing you need to be careful of is that you should only start collecting coverage once you've sampled at least 2 values (so that you have a previous). With transition coverage, the tool would do this for you under the hood.
The best way I can think of doing it is to wrap the covergroup inside a class:
class cg_wrapper #(int unsigned WIDTH = 3);
covergroup cg with function sample(bit [WIDTH-1 : 0] val,
bit [WIDTH-1 : 0] prev
);
coverpoint val;
coverpoint prev;
cross prev, val;
endgroup
function new();
cg = new();
endfunction
// ...
endclass
The class would keep track of the previous value and whether a previous value was collected (i.e. we tried to sample a second value):
class cg_wrapper #(int unsigned WIDTH = 3);
protected bit has_prev;
protected bit [WIDTH-1 : 0] prev;
// ...
endclass
To ensure that coverage is sampled at the appropriate points, the class would expose a sample(...) function (similar to what a covergroup has) that handles sampling the actual covergroup and storing the previous value:
class cg_wrapper #(int unsigned WIDTH = 3);
// ...
function void sample(bit [WIDTH-1 : 0] val);
if (has_prev)
cg.sample(val, prev);
prev = val;
has_prev = 1;
endfunction
endclass
This will ensure that you'll get meaningful crosses. For example, calling sample(...) twice with values 0 and 1, will result in only a single "transition" from 0 to 1 (i.e. one bin in the cross getting filled).
If you want to start excluding bins the "transitions" you can use a lot different ways to do that. For example, to exclude identical transitions, you could do:
cross prev, val {
ignore_bins ignore =
(binsof (val) && binsof (prev)) with (prev == val);
}
This ignores transitions of type 0 => 0, 1 => 1, 2 => 2, etc.
There's also a nice article from AMIQ Consulting showcasing some cool ways of specifying cross bins.
Your first solution needs little modification. You have to use [] after bin name to make it auto bin. I think that is the reason why it was not working for you.
cover_point_y : coverpoint y {
bins transitions[] = ( 0, 1 => 0, 1 );
}
Assuming you want to cover consecutive increments a cover property could do the trick:
bit [7:0] y;
property y_inc(int n); #(posedge clk) y == $past(y+1)[*n]; endproperty
y_inc_3: cover property (y_inc(3));
y_inc_full: cover property (y_inc((1<<$bits(y))-1));

Resources