fvutils / pyvsc

Python packages providing a library for Verification Stimulus and Coverage
https://fvutils.github.io/pyvsc
Apache License 2.0
113 stars 26 forks source link

Issue with randomizing enum types #15

Closed aneels3 closed 4 years ago

aneels3 commented 4 years ago

I have an enum class my_enum of 5 elements. Is there any way to randomly pick 3 elements of enum class in a class variable for each randomization? Such that I can use the variable by slicing elsewhere in the code.

The intention is to create a list of random enum elements of a fixed size. I have tried with variable_name = vsc.randsz_list(vsc.rand_enum_t(enum_class)) but it doesn't works well.

import vsc
from enum import Enum, auto

class my_enum(Enum):
    a = auto()
    b = auto()
    c = auto()
    d = auto()
    e = auto()

@vsc.randobj
class my_class(object):
    def __init__(self):
        self.variable = vsc.rand_enum_t(my_enum)

    @vsc.constraint
    def variable_c(self):
        self.variable.not_inside(vsc.rangelist(my_enum.a, my_enum.c))

inst = my_class()
inst.randomize()
print("Result = {}".format(inst.variable))

The above code snippet gives me a single enum element.

I want to make the self.variable as a list of a particular size, especially for enumerated types.

Please correct me if I'm missing something here.

Apart from the above issue

import vsc
from enum import Enum, auto

class my_enum(Enum):
    a = auto()
    b = auto()
    c = auto()
    d = auto()
    e = auto()

@vsc.randobj
class my_class(object):
    def __init__(self):
        self.variable1 = vsc.rand_enum_t(my_enum)
        self.variable2 = vsc.rand_enum_t(my_enum)
        self.variable3 = vsc.rand_enum_t(my_enum)

    @vsc.constraint
    def variable_c(self):
        # Situation 1
        self.variable1.not_inside(vsc.rangelist(self.variable2, self.variable3))

        # Situation 2
        self.variable1.not_inside(vsc.rangelist(self.variable2, self.variable3, my_enum.a))

inst = my_class()
inst.randomize()
print("Result = {}".format(inst.variable1))

For Situation 1 I am getting the same result even after iterating the randomize() method more than once. The result is always the first element of enum class i.e a

For Situation 2 I am getting an key error

I think the key error is because of self,var1, and self.var2 which are of vsc.rand_enum_t type otherwise my_enum.b, my_enum.a, my_enum.c works well. The Intention is to use the randomly generated enum values inside the vsc.rangelist clause with my_enum.a for self.variable1 constraint.

Let me know if I am missing something here. Thanks!

mballance commented 4 years ago

Hi Anil, Ideally you could handle this case with a fixed-size random list. In other words something like this:

   self.values = vsc.rand_list_t(enum_t(my_enum), sz=3)

I can see that this doesn't work, but will work on making it work.

Best Regards, Matthew

mballance commented 4 years ago

Hi Anil, Okay, I was able to make good progress this evening on this issue. Lists now properly-support enumerated-type elements, and you can use the 'unique' constraint on lists. Have a look at the following test, which I think is pretty close to what you're looking for based on the problem statement. https://github.com/fvutils/pyvsc/blob/33c5014bd3738f79eecc8b67150ae4e730f84f19/ve/unit/test_list_scalar.py#L157-L185 I've released this as 0.0.6 on PyPi if you're getting releases that way. Best Regards, Matthew

aneels3 commented 4 years ago

Hi Matthew Thanks for bringing this up and releasing the same on PyPi. It solves my query related to creating the list of enum types.

But for the second part of this issue, it can't be achieved using vsc.unique()

Let's take a dummy example

import vsc
from enum import Enum, auto 
class my_e(Enum):
    num1= 0
    num2= auto()
    num3 = auto()
    num4 = auto()
    num5 = auto()
    num6 = auto()
@vsc.randobj
class my_cls(object):
    def __init__(self):
        self.a = vsc.rand_list_t(vsc.enum_t(my_e), sz=3)  # self.a is a list of size 3
        self.b = vsc.rand_enum_t(my_e)
        self.c = vsc.rand_enum_t(my_e)

    @vsc.constraint
    def a_c(self):
        self.a not in vsc.rangelist(self.b, self.c, my_e.num2, my_e.num3) # I want self.a never get randomize to num2 and num3 value

using

vsc.unique(self.a, self.b, self.c) # We can get num2 and num3 in this case for self.a

I have tried with vsc.foreach for this constraint as self.a is finally a list of a particular size. (Not working, getting the same enum element throughout the list)

Can we use not_inside or not in for the rand_list of enum types?

Thank you!

mballance commented 4 years ago

Reopening, since it seems there's an additional issue

mballance commented 4 years ago

Hi @aneels3, I think 'unique' is the best way to accomplish this. Here is the test that I created from your example, which appears to work for me. Please re-open the issue if you still encounter issues.

Best Regards, Matthew

    def test_unique_list(self):
        class my_e(Enum):
            num1= 0
            num2= auto()
            num3 = auto()
            num4 = auto()
            num5 = auto()
            num6 = auto()

        @vsc.randobj
        class my_cls(object):
            def __init__(self):
                self.a = vsc.rand_list_t(vsc.enum_t(my_e), sz=3)  # self.a is a list of size 3
                self.b = vsc.rand_enum_t(my_e)
                self.c = vsc.rand_enum_t(my_e)

            @vsc.constraint
            def a_c(self):
                vsc.unique(self.a, self.b, self.c)

        my = my_cls()

        for i in range(10):
            my.randomize()
            total_l = []
            for av in my.a:
                total_l.append(av)
            total_l.append(my.b)
            total_l.append(my.c)

            print("a=%s b=%s c=%s" % (str(my.a), str(my.b), str(my.c)))
            for j in range(len(total_l)):
                for k in range(j+1, len(total_l)):
                    self.assertNotEqual(total_l[j], total_l[k])