SystemVerilog Constraint to populate unique values into a 2d fixed-size array without using the unique keyword

I am trying to populate unique values into a 2d fixed-size array without using the unique keyword
Can you please help me understand why would my following code not give me unique values?

class packet;
  rand bit [3:0] array[4][4];
  int i,j,a,b;

  constraint unique_elements {foreach (array[i][j]) {
    foreach (array[a][b]){
      (!(a==i && b==j)) -> array[a][b] != array [i][j];
    }
  }}
                
  function void print();
    for (int i = 0; i < 4; i++) begin
      $display("\n");
      for (int j = 0; j < 4; j++) begin
        $write("[%0d]\t",array[i][j]); 
      end 
    end
  endfunction 
endclass



module test;
  packet p;
  
  initial begin
    p=new();
      p.randomize;
      p.print();
  end
endmodule

In reply to sfenil1804:

The foreach loop you are using is not legal syntax for the very problem you are running into. You are only allowed one set of [] brackets in a foreach loop, and the variables inside the brackets are local iterator variables. In your case, the first set of brackets are being treated as a state variable, whose value is always 0. Many people have incorrectly written code like

foreach(array[A]) {
    ...
    foreach(array[A][B]) {...} 
    }

expecting the inner foreach loop to only iterate over [B] while the outer foreach loop iterates over [A]. The correct and legal way of writing this is

foreach(array[A]) {
    ...
    foreach(array[,B]) {...} 
    }

and the correct and legal way of writing your constraint is

//int i,j,a,b; no need to. declare here as they are implicitly declared by foreach
constraint unique_elements {foreach (array[i,j]) {
    foreach (array[a,b]){
      (!(a==i && b==j)) -> array[a][b] != array [i][j];
    }
  }}

In reply to dave_59:

Thank you, I understood the mistake.
It works as I intended now!

In reply to sfenil1804:

Could you please explain whats happening in the two foreach loops ? why do we need the condition !(a==i && b==j) ? is the first foreach loop creating a randomized matrix and the second matrix trying to make the elements unique by iterating the first one ?

constraint unique_elements {foreach (array[i][j]) {
    foreach (array[a][b]){
      (!(a==i && b==j)) -> array[a][b] != array [i][j];
    }
  }}

In reply to diptishe:

The two for each loops are both iterating over the same array so that every element gets compared with every other element. The !(a==i && b==j) implication prevents elements from being compared with themselves