Write constraint for an integer array with 10 elements such that exactly 3 of them are same and rest are unique


module abc;
  class aa;
    rand int unsigned val[10];
    rand int unsigned r_index1,r_index2,r_index3;
    
    constraint s1 {
      r_index1 inside {[0:9]};
      r_index2 inside {[0:9]};
      r_index3 inside {[0:9]};
      r_index1 != r_index2;
      r_index1 != r_index3;
      r_index3 != r_index2;

      
      
      foreach(val[i]){ val[i] < 10; }
        
      foreach(val[i]){
        foreach(val[j]){
          if(i != j && i!=r_index1  && j!=r_index1)
            val[i] != val[j];
        }
      }
          
        val[r_index1] == val[r_index2];
        val[r_index1] == val[r_index3];   
    }	
  endclass
        
  initial begin
    aa a1 = new();
    a1.randomize();
    $display(a1.r_index1, a1.r_index2,a1.r_index3);
    $display(a1.val);
  end
endmodule

Seems when i run this code,its going to infinite loop.May i know how to solve it.

In reply to dve12:

In the second foreach you meant a[i]!=r_index1 && a[j]!=r_index1 instead of i!=r_index1 && j!=r_index1.



module abc;
  class aa;
    rand int unsigned val[10];
    rand int unsigned r_index1,r_index2,r_index3;
 
    constraint s1 {
      r_index1 inside {[0:9]};
      r_index2 inside {[0:9]};
      r_index3 inside {[0:9]};
      r_index1 != r_index2;
      r_index1 != r_index3;
      r_index3 != r_index2;
 
 
      
      foreach(val[i]){
        val[i] < 10 ;  }
 
      foreach(val[i]){
        foreach(val[j]){
          if(i != j && val[i]!=r_index1  && val[j]!=r_index1)
            val[i] != val[j];
        }
      }
 
        val[r_index1] == val[r_index2];
        val[r_index1] == val[r_index3];   
    }	
  endclass
 aa a1 ;
  initial begin
    a1 = new();
    assert(a1.randomize());
    $display(a1.r_index1, a1.r_index2,a1.r_index3);
    $display(a1.val);
  end
endmodule


In reply to dve12:

You have made the constraints much more complex than they need to be, And technically, you are not allowed a random index into a random array variable.

module abc;
  class aa;
    rand byte unsigned val[10], val3;
 
    constraint s1 {
      foreach(val[i]) {
        val[i] < 10;
        // every value except val3 must appear only once
        val[i] != val3 -> val.sum() with (int'(item==val[i]))== 1;
      }
      // val3 must appear three times in the array
      val.sum() with (int'(item==val3)) == 3;
                      }
  endclass
                      
  aa a1 = new();

  initial repeat (10) begin
    a1.randomize();
    $display("%p %d", a1.val, a1.val3);
  end
endmodule

In reply to dve12:

This is one of the compact way I could think of

class generate_array#(parameter repeat_n = 3, parameter arr_size = 10, parameter elem_dim = 4);
   rand bit [elem_dim-1:0] a[arr_size];
   rand bit [elem_dim-1:0] b;
   
   // unique and repeat 3 times speciefied by the param
   constraint unique_and_repeat {
       b inside {a};
       foreach(a[i])
            a.sum() with (8'(item == a[i])) == ((a[i]%b == 0) & (a[i]/b ==1) ? repeat_n:1);
   }
   
   function void post_randomize();
       a.sort() ;  
   endfunction 
endclass
 
module top_tb;
   // PARAM
   parameter repeat_n = 3; 
   parameter arr_size = 10;
   parameter elem_dim = 4; 

   generate_array#(repeat_n,arr_size,elem_dim) my_arr;
 
   initial begin   
      my_arr = new();  
      repeat(arr_size) begin
        if(my_arr.randomize()) begin       
            $display(" b is %0h " , my_arr.b);
            $display(" a is %0p " , my_arr.a);       
        end  
      else 
          $display("Fail in randomization");
      end
   end  
endmodule

In reply to dave_59:

In reply to dve12:
You have made the constraints much more complex than they need to be, And technically, you are not allowed a random index into a random array variable.

module abc;
class aa;
rand byte unsigned val[10], val3;
constraint s1 {
foreach(val[i]) {
val[i] < 10;
// every value except val3 must appear only once
val[i] != val3 -> val.sum() with (int'(item==val[i]))== 1;
}
// val3 must appear three times in the array
val.sum() with (int'(item==val3)) == 3;
}
endclass
aa a1 = new();
initial repeat (10) begin
a1.randomize();
$display("%p %d", a1.val, a1.val3);
end
endmodule

Hi Dave,

Could you please explain what the above code is doing.

Thanks.

In reply to totochan1985:

It’s doing exactly what the original poster asked for. Can you highlight a piece of syntax that you do not understand?

1 Like

In reply to dave_59:

// every value except val3 must appear only once
        val[i] != val3 -> val.sum() with (int'(item==val[i]))== 1;
      }
      // val3 must appear three times in the array
      val.sum() with (int'(item==val3)) == 3;

I have trouble understanding these lines. What exactly ‘item’ refers to here?
What are these lines achieving exactly?

In reply to totochan1985:

sum() is one of the array reduction methods (See section 7.12.3 Array reduction methods).

When used in a constraint, these methods get unrolled into a big expression (Section 18.5.8.2 Array reduction iterative constraints)

‘item’ is replaced with each element of the array.

val.sum() with (int'(item==val3))

becomes

int'(val[0]==val3) + int'(val[1]==val3) + int'(val[2]==val3) + ... +int'(val[9]==val3)

The cast to int is needed because otherwise the sum would be limited to 1-bit, which is the result of the equality operator.

In reply to dave_59:

In reply to totochan1985:
sum() is one of the array reduction methods (See section 7.12.3 Array reduction methods).
When used in a constraint, these methods get unrolled into a big expression (Section 18.5.8.2 Array reduction iterative constraints)
‘item’ is replaced with each element of the array.

val.sum() with (int'(item==val3))

becomes

int'(val[0]==val3) + int'(val[1]==val3) + int'(val[2]==val3) + ... +int'(val[9]==val3)

The cast to int is needed because otherwise the sum would be limited to 1-bit, which is the result of the equality operator.

Thanks for the response. I now understand the solution.

class A;
rand int arr,res_arr;
constraint c {
foreach (arr[i]) {
arr[i] >0; //optional for clarity
arr[i] <100; //optional for clarity
arr[0] ==arr[1];
arr[1]==arr[2];
if (i>=3 && i<=9)
arr[i]!=arr[i+1];
}
};

function void post_randomize();
$display (“shuffle”);
arr.shuffle();
endfunction

endclass
program main ();
initial begin
A aa;

aa = new();
aa.arr= new[11];

aa.randomize();
foreach (aa.arr[i]) begin
  $display ("%0d",aa.arr[i]);
end

end

endprogram