Constraint for repeating numbers in an array in a unique pattern

I am trying to solve a constraint where an array A (say int) has a certain configurable length and its contents are repeated ‘k’ times each except for 1 element that is unique to the array.

Example: A (say length 10 and k = 3) = {4, 4, 4, 7, 7, 7, 10, 10, 10, 30}
Each value is repeated k times and 30 is unique to the array.

I have been able to solve it in this way:

Given size of the array and k, I generate a value of unique number of elements required. This is pseudo code and I paraphrase but you get the idea.

rand int uniq_e = (A.size()/k) + 1;
rand int uniq_A of size uniq_e.
unique {uniq_A}

Then in post randomize, just replicate all but 1 element k times and create array A.

However, is there a better way to solve this using constraint blocks directly. (tried A.xor and A.sum together but does not seem to work)

In reply to kernalmode1:

Was not entirely clear if length and k were set before calling randomize, but this should work in most cases.

module top;
  class C;
    rand bit[4:0] A[], uniq_A[];
    rand bit [7:0] length,k;
  
    constraint sizes { 
      length == A.size();
      length % k == 1;
      length / k == uniq_A.size();
    }
    constraint uniqueness {
      unique {uniq_A}; 
      foreach(uniq_A[i]) A.sum() with (int'(item==uniq_A[i])) == k;
    }
  endclass
  C c = new();
  initial repeat(5) begin
    assert(c.randomize() with {length == 19;});
    c.A.sort();
    $display("%p", c);
  end
endmodule

In reply to dave_59:

Thanks you as always Dave. I got most of the code and updated a couple of lines to suit the requirements.


module top;
  class C;
    rand bit[4:0] A[], uniq_A[];
    rand bit [7:0] length,k;
 
    constraint sizes { 
      length == A.size();
      length % k >= 1;
      uniq_A.size() == (length/k) +1;
    }
    constraint uniqueness {
      unique {uniq_A}; 
      foreach(uniq_A[i]) {
        if (i<(uniq_A.size()-1)) {
          A.sum() with (int'(item==uniq_A[i])) == k;
        }
        else {
          A.sum() with (int'(item==uniq_A[i])) == 1;
        }
      }
    }
  endclass
  C c = new();
  initial repeat(5) begin
    assert(c.randomize() with {length == 17; k== 4;});
    c.A.sort();
    $display("%p", c);
  end
endmodule

Surprising one of the simulators does not like this constraint and takes a really long time and I had to kill it. Anyhow cdns, questa worked.

In reply to kernalmode1:
Note that both my and your example meet the same requirements.

In reply to dave_59:

Ah, true.

In reply to dave_59:

In reply to kernalmode1:
Was not entirely clear if length and k were set before calling randomize, but this should work in most cases.

module top;
class C;
rand bit[4:0] A[], uniq_A[];
rand bit [7:0] length,k;
constraint sizes { 
length == A.size();
length % k == 1;
length / k == uniq_A.size();
}
constraint uniqueness {
unique {uniq_A}; 
foreach(uniq_A[i]) A.sum() with (int'(item==uniq_A[i])) == k;
}
endclass
C c = new();
initial repeat(5) begin
assert(c.randomize() with {length == 19;});
c.A.sort();
$display("%p", c);
end
endmodule

Hi Dave

I understand your solution. I also solved this using post_randomize. Is this better than doing in post_randomize as kernal1mode suggested? or both ways can be used interchangeably.

In reply to JGu:

A solution that works without post_randomize is always preferred over one that uses it. This makes it easer to add and override constraints.