Help with

I could not answer this question completely. Only solved for the size of the arrays; Your help will be appreciated:

// There are 40 cards of 4 colors RED,BLUE,GREEN,YELLOW and numbered from 0-9.
// I would like to pick set of 7 cards comprising of 2 sets.
//Set 1 has to have a minimum of 3 cards in sequence. Cards have to be of the same color.
//Set 2 has to have a minimum of 3 cards. Cards have to be of the same number but different color.

//typedef enum {RED, BLUE, GREEN, YELLOW} color_t;
  rand color_t same_color_cards[];
  rand color_t same_number_cards[];
  constraint total_size {(same_color_cards.size() + same_number_cards.size()) == 7;}
  constraint same_color_size {same_color_cards.size() inside {[3:4]};}
  constraint same_number_size {same_number_cards.size() inside {[3:4]};}

In reply to gkaragatchliev:

The following code implements your specs:

typedef enum {RED, BLUE, GREEN, YELLOW} color_t;

class card;
  rand color_t color;
  rand bit[3:0] number;
  constraint max_9 {number inside {[0:9]};}
endclass

class set_7cards;
  rand color_t colors[4];
  rand card set1[];
  rand card set2[];
  
  function void pre_randomize();
    set1 = new[4];
    set2 = new[4];
    foreach(set1[i]) set1[i] = new();
    foreach(set2[i]) set2[i] = new();
  endfunction

  constraint c_set1_set2_sizes {
    set1.size() inside {[3:4]};
    set2.size() inside {[3:4]};
    set1.size() + set2.size() == 7;
  } 
  constraint c_colors{
    unique {colors};
  }
  constraint c_set1 {
    foreach(set1[i]){
      if(i != 0){
      	set1[i].color == set1[i-1].color;
        set1[i].number == 1 + set1[i-1].number;
      }
    }
  }
  constraint c_set2 {
    foreach(set2[i]){
      set2[i].color == colors[i];
      if(i == 0){
        !(set2[i].number inside{[set1[0].number:set1[0].number+3]});
      } else {
        set2[i].number == set2[i-1].number;
      }
    }
  }
endclass

module testbench;
  initial begin
    set_7cards ex_obj;
    ex_obj = new();
    
    repeat(10) begin
      ex_obj.randomize();
      $display("");
      foreach (ex_obj.set1[i]) $display("==> ex_obj.set1[%0d].color = %0s  -  ex_obj.set1[%0d],number = %0d", i, ex_obj.set1[i].color, i, ex_obj.set1[i].number);
      foreach (ex_obj.set2[i]) $display("==> ex_obj.set2[%0d].color = %0s  -  ex_obj.set2[%0d],number = %0d", i, ex_obj.set2[i].color, i, ex_obj.set2[i].number);
    end
  end
endmodule

1 Like

Another suggestion :)

//----------------------------------------------//
class stimuli;
 
  typedef enum bit[1:0] {RED, BLUE, GREEN, YELLOW}   COLOR;
  typedef struct packed {COLOR c; int unsigned num;} CARD;
 
  rand COLOR c_set_1[];
  rand COLOR c_set_2[];
  rand int unsigned n_set_1[];
  rand int unsigned n_set_2[];
 
  CARD sol[7];
 
  constraint c_sizes {(this.c_set_1.size()+this.c_set_2.size()) == 7;
                      this.c_set_1.size() >= 3;
                      this.c_set_2.size() >= 3;
                      this.c_set_1.size() == this.n_set_1.size();
                      this.c_set_2.size() == this.n_set_2.size();}
 
  constraint co_set_1 {
    foreach (this.n_set_1[i]) {
      this.n_set_1[i] inside{[0:9]};
      (i > 0) -> (this.n_set_1[i] == this.n_set_1[i-1]+1);
      (i > 0) -> (this.c_set_1[i] == this.c_set_1[i-1]);
    }
  }
 
  constraint co_set_2 {
    unique {this.c_set_2};
    // To prevent having a repeated card between sets, if commented the checker in the module will fail
    unique {this.n_set_2[0], this.n_set_1};
    foreach (this.n_set_2[i]) {
      this.n_set_2[i] inside{[0:9]};
      (i > 0) -> (this.n_set_2[i] == this.n_set_2[i-1]);
    }
  }
 
  function void post_randomize();
    // Filing the solution array
    foreach(this.c_set_1[i]) begin
      this.sol[i].c   = this.c_set_1[i];
      this.sol[i].num = this.n_set_1[i];
    end
    foreach(this.c_set_2[i]) begin
      this.sol[i+this.c_set_1.size()].c   = this.c_set_2[i];
      this.sol[i+this.c_set_1.size()].num = this.n_set_2[i];
    end
  endfunction
endclass
 
//----------------------------------------------//
module test;
   initial begin
      stimuli s;
      stimuli::CARD q[$];
      s = new();
     repeat(10) begin
        s.randomize();
        $display("%p", s.sol);
        // Check if there is a repeated card
        q = s.sol.unique;
        if($size(q) !== $size(s.sol)) begin
          $error("There is a repeated card in between sets!!!!");
          $finish;
        end
      end
   end
endmodule

In reply to M.Wafa:

Hi M.Wafa,

In your solution,

Only below set is covered.

// 1. array of different color is followed array of same color

// 2. array of same values is followed by array of different values

Other possibility is

// 1. array of same color and array of different color

// 2. array of different values and array of same values

which is not covered.



class cards;
  typedef enum {RED,BLUE,GREEEN,YELLOW} colour_e;
  rand colour_e col_1[],col_2[],col;
  rand bit[3:0] val_1[],val_2[],val;
  randc bit mode;
  colour_e colour_array[];
  bit[3:0] val_array[];

  // There are set of 2 arrays one set for colours and other set for values
  constraint val_size_c { 
                          col_1.size() inside{3,4};
                          col_2.size() inside{3,4};
                          val_1.size() inside{3,4};
                          val_2.size() inside{3,4};

                          col_1.size() == val_1.size();
                          col_2.size() == val_2.size();

                          col_1.size() + col_2.size() == 7;
                          val_1.size() + val_2.size() == 7;
                        }

  // col_1 array elements are of different colour
  // val_1 array elements are in sequence
  constraint uniq_c { 
                     unique {col_1};
                     foreach(val_1[i]) {
                        val_1[i] inside {[0:9]};
                        if(i) {
                          val_1[i] == val_1[i-1]+1; // Incr order
                        }
                      }
                    }

  // col_2 array elements are of same colour
  // val_2 array elements are of same value
  constraint same_c {
                      foreach(col_2[i]) {
                        val_2[i] inside {[0:9]};
                        if(i) {
                          col_2[i] == col_2[i-1]; // Same colour
                          val_2[i] == val_2[i-1]; // same value
                        }
                      }
                    }

  function void post_randomize();
    colour_array = new[col_1.size() + col_2.size()];
    val_array    = new[val_1.size() + val_2.size()];
    $display("mode =%0d",mode);
  
    // Based on mode concatenate the arrays,
    // Mode 0 :
    //    1. array of different colour and array of same colour
    //    2. array of same values and array of differnt values
    // Mode 0 :
    //    1. array of same colour and array of different colour
    //    2. array of different values and array of same values
    case(mode)
      0 : begin
        colour_array = {col_1,col_2};
        val_array    = {val_2,val_1};
      end
      1 : begin
        colour_array = {col_2,col_1};
        val_array    = {val_1,val_2};
      end
    endcase
  endfunction

endclass


module test;
 cards cc;
 bit suc;
 initial begin
   cc = new();
   repeat(10) begin
     suc = cc.randomize();
     $display("*******************************************************************");
     $display("Value  = %p",cc.val_array);
     $display("Colour = %p",cc.colour_array);
     $display("*******************************************************************");
   end  
 end
endmodule




In reply to Tulasiram:

Hi Tulasiram,

Other possibility is
// 1. array of same color and array of different color
// 2. array of different values and array of same values
which is not covered.

Actually nothing mentioned in the question for this, i.e. I named the two sets: set1 & set2 but it doesn’t matter which one is the first one and you can name them: setSameColor & setSameNumber or any other names.

  1. Please notice that your answer doesn’t really follow the requirements mentioned in the question, separating the arrays and concatenate them in post_randomize actually produce some incorrect results, also doesn’t consider that we are picking cards from 40 cards pool, i.e. no cards should be picked twice.

run -all

mode =0

*******************************************************************

Value = '{9, 9, 9, 0, 1, 2, 3}

Colour = '{GREEEN, BLUE, YELLOW, RED, YELLOW, YELLOW, YELLOW}

*******************************************************************

mode =1

*******************************************************************

Value = '{2, 3, 4, 5, 0, 0, 0}

Colour = '{BLUE, BLUE, BLUE, YELLOW, RED, BLUE, GREEEN}

*******************************************************************

mode =0

*******************************************************************

Value = '{1, 1, 1, 1, 2, 3, 4}

Colour = '{YELLOW, GREEEN, RED, GREEEN, GREEEN, GREEEN, GREEEN}

*******************************************************************

Please give it a try (2) - EDA Playground … the above is one run and you see that the 4th item in the first and second results doesn’t belong to any set, and in the third result: GREEN-1 card is picked twice

In reply to Ahmed Kelany:

Hi Ahmed,

I’m seeing that there is no constraints to prevent picking a card more than once, please give it a try: (1) - EDA Playground

Thanks,

In reply to M.Wafa:

Here is a different approach. Create a deck of cards and have the constraints solver pick a card from the deck

module test;

  typedef enum {RED, BLUE, GREEN, YELLOW}   color_e;
  typedef struct {
    color_e color;
    int unsigned number;
  } card_s; 
class Problem;
  card_s Deck[$];
  rand int unsigned set1[], set2[]; // Represents an index into the Deck
  function new;
    color_e c_itr; // color iterator
    int     n_itr; // number iterator
    // create full deck of 40 cards
    do begin
      for (n_itr=0;n_itr<10;n_itr++) // loop over 10 numbers
        Deck.push_back('{c_itr,n_itr});
      c_itr = c_itr.next;
    end while (c_itr != c_itr.first()); // loop over 4 colors
  endfunction
  
  constraint c_sizes {
    set1.size inside {[3:4]};
    set2.size inside {[3:4]};
    (set1.size + set2.size) == 7;
  }
  constraint c_picks {
    foreach (set1[i]) set1[i] < Deck.size();
    foreach (set2[i]) set2[i] < Deck.size();
    unique {set1, set2}; // can only pick a card once 
  }
  constraint c_set1 {
    foreach (set1[i]) i > 0 -> {
      Deck[set1[i]].color == Deck[set1[i-1]].color; // colors are the same
      Deck[set1[i]].number == Deck[set1[i-1]].number + 1; // numbers in sequence 
    }}
  constraint c_set2 {
    foreach (set2[i]) foreach (set2[j]) i != j ->
      Deck[set2[i]].color != Deck[set2[j]].color;  // colors are different 
    foreach (set2[i]) i > 0 -> {
      Deck[set2[i]].number == Deck[set2[i-1]].number; // numbers are the same
    }}
endclass
    
  Problem P = new;
  initial repeat (10) begin
     assert (P.randomize());
     $display("set1");
     foreach (P.set1[i]) $write(" %p ",P.Deck[P.set1[i]]);
     $display("\nset2");
     foreach (P.set2[i]) $write(" %p ",P.Deck[P.set2[i]]);
     $display();

   end
endmodule

In reply to dave_59:

Hi Dave,
What exactly is going on here:

constraint c_picks {
    foreach (set1[i]) set1[i] < Deck.size();
    foreach (set2[i]) set2[i] < Deck.size();
    unique {set1, set2}; // can only pick a card once 
  }

isn’t it enough to use unique on the set? I am failing to understand the two foreach:

In reply to M.Wafa:

Oh My bad.
Thanks M.Wafa for pointing me the mistakes. I have fixed them.
Fixed Code is



 class cards;
   typedef enum {RED,BLUE,GREEEN,YELLOW} colour_e;
   rand colour_e col_1[],col_2[],col;
   rand bit[3:0] val_1[],val_2[],val;
   randc bit mode;
   colour_e colour_array[];
   bit[3:0] val_array[];
 
   // There are set of 2 arrays one set for colours and other set for values
   constraint val_size_c { 
                           col_1.size() inside{3,4};
                           col_2.size() inside{3,4};
                           val_1.size() inside{3,4};
                           val_2.size() inside{3,4};
 
                           col_1.size() == val_2.size();
                           col_2.size() == val_1.size();
 
                           col_1.size() + col_2.size() == 7;
                           val_1.size() + val_2.size() == 7;
                         }
 
   // col_1 array elements are of different colour
   // val_1 array elements are in sequence
   constraint uniq_c { 
                      unique {col_1};
                      foreach(val_1[i]) {
                         val_1[i] inside {[0:9]};
                         if(i) {
                           val_1[i] == val_1[i-1]+1; // Incr order
                         }
                       }
                     }
 
   // col_2 array elements are of same colour
   // val_2 array elements are of same value
   constraint same_c {
                       foreach(val_2[i]) {
                         val_2[i] inside {[0:9]};
                         if(i) {
                           val_2[i] == val_2[i-1]; // same value
                         }
                       }

                       foreach(col_2[i]) {
                         if(i) {
                           col_2[i] == col_2[i-1]; // Same colour
                         }
                       }
                     }
    constraint uniq_bw_array_c {
              unique {val_2[0],val_1};  // To have unique values no repetitions
    }
 
   function void post_randomize();
     colour_array = new[col_1.size() + col_2.size()];
     val_array    = new[val_1.size() + val_2.size()];
     $display("mode =%0d",mode);
   
     // Based on mode concatenate the arrays,
     // Mode 0 :
     //    1. array of different colour and array of same colour
     //    2. array of same values and array of differnt values
     // Mode 0 :
     //    1. array of same colour and array of different colour
     //    2. array of different values and array of same values
     case(mode)
       0 : begin
         colour_array = {col_1,col_2};
         val_array    = {val_2,val_1};
       end
       1 : begin
         colour_array = {col_2,col_1};
         val_array    = {val_1,val_2};
       end
     endcase
   endfunction
 
 endclass
 
 
 module test;
  cards cc;
  bit suc;
  initial begin
    cc = new();
    repeat(10) begin
      suc = cc.randomize();
      $display("*******************************************************************");
      $display("Value  = %p",cc.val_array);
      $display("Colour = %p",cc.colour_array);
      $display("*******************************************************************");
    end  
  end
 endmodule



Tried same in eda playground Edit code - EDA Playground
It is working as expected.

In reply to M.Wafa:

Updated the solution and added a checker for it :)

// Another approach with helper array


typedef enum { RED, ORANGE, BLUE, GREEN, YELLOW } colours_e;

class cards extends uvm_object;

    rand colours_e colour;
    rand bit [3:0] number;

    `uvm_object_utils_begin(cards)
        `uvm_field_enum(colours_e, colour, UVM_ALL_ON)
        `uvm_field_int(number, UVM_ALL_ON)
    `uvm_component_utils_end

    function new(string name="cards");
        super.new(name);
    endfunction : new

    constraint c_number {
        number <= 9;
    }

endclass : cards

class two_sets extends uvm_object;
    `uvm_object_utils(two_sets)

    rand cards set_1[];
    rand cards set_2[];
  
    bit [3:0] arr_size;

    rand colours_e s1_same_colour_helper_array[];
    rand bit [3:0] s1_diff_num_helper_array[];    
    rand bit [2:0] s1_ref_index;  // Randomly choosing one index as reference to
                                  // get same colour

    rand colours_e s2_diff_colour_helper_array[];
    rand bit [3:0] s2_same_num_helper_array[];    
    rand bit [2:0] s2_ref_index; // Randomly choosing one index as reference to
                                 // get same number

    function new(string name="two_sets");
        super.new(name);
    endfunction : new

    function void pre_randomize();        
        arr_size = $urandom_range(3,4);        
        set_1 = new[arr_size];
        set_2 = new[7-arr_size];
        foreach(set_1[ii])
            set_1[ii] = cards::type_id::create($psprintf("set_1_%0d",ii));
        foreach(set_2[ii])
            set_2[ii] = cards::type_id::create($psprintf("set_2_%0d",ii));
    endfunction : pre_randomize

    // Set1 has same colour but different numbers
    constraint c_set1 {
        s1_same_colour_helper_array.size() == arr_size;
        s1_diff_num_helper_array.size() == arr_size;
        s1_ref_index inside {[1:arr_size]};
        foreach(set_1[ii]) {
            s1_same_colour_helper_array[ii] == set_1[ii].colour;
            s1_diff_num_helper_array[ii] == set_1[ii].number;
        }              
        s1_same_colour_helper_array.sum() with (int'(item==set_1[s1_ref_index].colour?1:0)) >= 3;
        unique{s1_diff_num_helper_array};
    }

    // Set2 has different colour with same number
    constraint c_set2 {
        s2_diff_colour_helper_array.size() == 7-arr_size;
        s2_same_num_helper_array.size() == 7-arr_size;
        s2_ref_index inside {[1:7-arr_size]};
        foreach(set_2[ii]) {
            s2_diff_colour_helper_array[ii] == set_2[ii].colour;
            s2_same_num_helper_array[ii] == set_2[ii].number;
        }
        unique{s2_diff_colour_helper_array};        
        s2_same_num_helper_array.sum() with (int'(item==set_2[s2_ref_index].number?1:0)) >= 3;
    }

    function void post_randomize();
        foreach(set_1[ii])
            `uvm_info("%s", set_1[ii].sprint(), UVM_NONE);
        foreach(set_2[ii])
            `uvm_info("%s", set_2[ii].sprint(), UVM_NONE);
    endfunction : post_randomize

endclass : two_sets


module tb();

    two_sets ts;

    initial begin
        ts = new();
        ts.randomize();
    end

endmodule : tb