3

I have a testcase in which the behavior seems wrong. I see that in all generations the num_of_red_shoes is high, while I would expect a more even distribution. What is the cause of this behavior and how can it be fixed?

<'
struct closet {
    kind:[SMALL,BIG];

    num_of_shoes:uint;
    num_of_red_shoes:uint;
    num_of_black_shoes:uint;
    num_of_yellow_shoes:uint;

    keep soft num_of_red_shoes < 10;
    keep soft num_of_black_shoes < 10;
    keep soft num_of_yellow_shoes < 10;

    keep num_of_yellow_shoes + num_of_black_shoes + num_of_red_shoes == num_of_shoes;

    when BIG closet {
        keep num_of_shoes in [50..100];
    };
};

extend sys {
    closets[100]:list of BIG closet;
};
'>

Generation results:

item   type        kind        num_of_sh*  num_of_re*  num_of_bl*  num_of_ye* 
---------------------------------------------------------------------------
0.     BIG closet  BIG         78          73          1           4           
1.     BIG closet  BIG         67          50          8           9           
2.     BIG closet  BIG         73          68          0           5           
3.     BIG closet  BIG         73          66          3           4           
4.     BIG closet  BIG         51          50          0           1           
5.     BIG closet  BIG         78          76          1           1           
6.     BIG closet  BIG         55          43          7           5           
7.     BIG closet  BIG         88          87          1           0           
8.     BIG closet  BIG         99          84          6           9           
9.     BIG closet  BIG         92          92          0           0           
10.    BIG closet  BIG         63          55          3           5           
11.    BIG closet  BIG         59          50          9           0           
12.    BIG closet  BIG         51          44          2           5           
13.    BIG closet  BIG         82          76          1           5           
14.    BIG closet  BIG         81          74          2           5           
15.    BIG closet  BIG         97          93          2           2           
16.    BIG closet  BIG         54          41          8           5           
17.    BIG closet  BIG         55          44          5           6           
18.    BIG closet  BIG         70          55          9           6           
19.    BIG closet  BIG         63          57          1           5  
Mysterion
  • 9,050
  • 3
  • 30
  • 52
SpecUser
  • 31
  • 1

4 Answers4

3

When there are contradicting soft constraints, Specman does not randomize the softs which are enforced, but rather gives priority to the constraints which were written last. Since the soft on red shoes was first in the test, it is the one which is always overridden.

If the softs are known to be mutually exclusive (which is not the case here) you could use a simple flag to randomly choose which soft should hold. e.g. the code would look like this:

flag:uint[0..2];

keep soft read_only(flag==0) => num_of_red_shoes < 10;
keep soft read_only(flag==1) => num_of_black_shoes < 10;
keep soft read_only(flag==2) => num_of_yellow_shoes < 10;

However, since here there is no knowledge in advance how many softs are expected to hold (and it's possible and two or all three will be satisfied) a more complex solution should be made. Here is a code which does this randomization:

struct closet {
    kind:[SMALL,BIG];

    num_of_shoes:uint;
    num_of_red_shoes:uint;
    num_of_black_shoes:uint;
    num_of_yellow_shoes:uint;

    //replaces the original soft constraints (if a flag is true the correlating
    //right-side implication will be enforced
    soft_flags[3]:list of bool;
    keep for each in soft_flags {
        soft it == TRUE;
    };

    //this list is used to shuffle the flags so their enforcement will be done
    //with even distribution
    soft_indices:list of uint;
    keep soft_indices.is_a_permutation({0;1;2});

    keep soft_flags[soft_indices[0]] => num_of_red_shoes < 10;
    keep soft_flags[soft_indices[1]] => num_of_black_shoes < 10;
    keep soft_flags[soft_indices[2]] => num_of_yellow_shoes < 10;

    keep num_of_yellow_shoes + num_of_black_shoes + num_of_red_shoes == num_of_shoes;
};
1

I'm not with Cadence, so I can't give you a definite answer. I think the solver will try to break as few constraints as possible and it just chooses the first one if finds (in your case the one for red shoes). Try changing the order and see if this changes (if the black constraint is first, I'd think you'll always get more black shoes).

As a solution, you could just remove the soft constraints when you have a big closet:

when BIG closet {
    keep num_of_red_shoes.reset_soft();
    keep num_of_black_shoes.reset_soft();
    keep num_of_yellow_shoes.reset_soft();
    keep num_of_shoes in [50..100];
};

If you want to randomly choose which one of them to disable (sometimes more than 10 red shoes, sometimes more than 10 black shoes, etc.), then you'll need a helper field:

when BIG closet {
    more_shoes : [ RED, BLACK, YELLOW ];

    keep more_shoes == RED => num_of_red_shoes.reset_soft();
    keep more_shoes == BLACK => num_of_black_shoes.reset_soft();
    keep more_shoes == YELLOW => num_of_yellow_shoes.reset_soft();
    keep num_of_shoes in [50..100];
};

It depends on what you mean by "a more even distribution".

Tudor Timi
  • 7,453
  • 1
  • 24
  • 53
1

There is no way to satisfy all of your hard and soft constraints for a BIG closet. Therefore Specman attempts to find a solution by ignoring some of your soft constraints. The IntelliGen constraint solver doesn't ignore all of the soft constraints, but attempts to find a solution while still using a subset. This is explained in the "Specman Generation User Guide" (sn_igenuser.pdf):

[S]oft constraints that are loaded later are considered to have a higher priority than soft constraints loaded previously."

In this case that means that Specman discards the soft constraint on red shoes and since it can find a solution still obeying the other soft constraints it does not discard them.

If you combine all of your soft constraints into one, then you will probably get the result you were hoping for:

 keep soft ((num_of_red_shoes    < 10) and (num_of_black_shoes < 10) and
            (num_of_yellow_shoes < 10));

There are advantages to giving later constraints priority: This means that using AOP you can add new soft constraints and they will get the highest priority.

Hackonteur
  • 821
  • 7
  • 12
1

For more distributed values, I would suggest the following. I'm sure you can follow the intended logic too.

var1, var2 : uint;
keep var1 in [0..30];
keep var2 in [0..30];

when BIG closet {
    keep num_of_shoes in [50..100];
    keep num_of_yellow_shoes == (num_of_shoes/3) - 15 + var1;
    keep num_of_black_shoes == (num_of_shoes - num_of_yellow_shoes)/2 - 15 + var2;
    keep num_of_red_shoes == num_of_shoes - (num_of_yellow_shoes - num_of_black_shoes);

keep gen (var1, var2) before (num_of_shoes);
    keep gen (num_of_shoes) before (num_of_yellow_shoes, num_of_black_shoes, num_of_red_shoes);
    keep gen (num_of_yellow_shoes) before (num_of_black_shoes, num_of_red_shoes);
    keep gen (num_of_black_shoes) before (num_of_red_shoes);
};