2D array constraint randomization

Hello,

I have a case where say an array[3][3] (9 elements) needs to be randomized such that sum of rows and columns is the same and all elements are unique.
While the sum of rows can be ensured using array.sum() == value how can I apply that to the column elements ?

parameter SIZE =3;

class ABC;
  rand bit[4:0] md_array [][]; 	
  
  constraint c_md_array { 
    md_array.size() == SIZE;
    foreach(md_array[k]) {
      md_array[k].size() == SIZE;
    }
    
    foreach(md_array[i]){
      md_array[i].sum() with (7'(item)) == 'd21;
      unique {md_array[i]};
    }
  }
endclass

In reply to vai_des:

I Hope below link will help you to find the solution.

https://verificationacademy.com/forums/systemverilog/magic-square-system-verilog

In reply to vai_des:


class like_sudoku;
 
  rand bit [4:0] a [3][3];
 
  constraint c1 {

        foreach(a[i,j]) {
            a.sum with (item.index(1) == i ? int'(item): 0) == 15; // rows
            a.sum with (item.index(2) == j ? int'(item): 0) == 15; // cols
        }
        unique {a};
  }


1 Like

In reply to prasadaddagarla:

That works great !

I tried a different approach that involves matrix transpose. I basically tried to solve the magic square problem (including the constraints on both the diagonals as well). Hope that helps!


class magic_square#(int grid_size=4);
  rand bit[4:0] rand_array[grid_size][grid_size];
  rand bit[4:0] rand_array_transpose[grid_size][grid_size];
  rand bit[4:0] diagonal_0[grid_size];
  rand bit[4:0] diagonal_1[grid_size];
  rand int unsigned rand_sum;
 
  constraint magic_square_cnstr {
    rand_sum >= 0;
    rand_sum <= 8'hFF;
 
    foreach(rand_array[i]) {
      unique{rand_array[i]};
      rand_array[i].sum() with (int'(item)) == rand_sum;
    }
 
    foreach(rand_array[i,j]) {
      rand_array_transpose[j][i] == rand_array[i][j];
      if (i==j) {
        diagonal_0[i] == rand_array[i][j];
      }
      if ((i+j) == grid_size-1) {
        diagonal_1[i] == rand_array[i][j];
      }
    }
 
    foreach(rand_array_transpose[i]) {
      unique{rand_array_transpose[i]};
      rand_array_transpose[i].sum() with (int'(item)) == rand_sum;
    }
 
    foreach(rand_array[i,j]) {
      foreach(rand_array[i1,j1]) {
        if ((i!=i1) && (j!=j1)) {
          rand_array[i][j] != rand_array[i1][j1];
        }
      }
    }
    diagonal_0.sum() with (int'(item)) == rand_sum;
    diagonal_1.sum() with (int'(item)) == rand_sum;                            
  }
 
  function post_randomize();
    string row_print;
    $display("Solving for grid_size:0x%0x sum:0x%0x", grid_size, rand_sum);
    foreach (rand_array[row]) begin
      row_print = {row_print,$sformatf("%p \n", rand_array[row])};
    end
    $display ("%s", row_print);
  endfunction // post_randomize
 
  endclass // magic_square
 
module magic_square();
 
initial begin
  magic_square #(4) ms = new();
  assert(ms.randomize());
 
end
 
endmodule // magic_square

In reply to prasadaddagarla:

Hey,

Have you tried this on multidimensional dynamic array?

I have tried and it give me below error,

class matrix_cons;
  
  rand bit [2:0] a [][];
  
  constraint c1 { a.size() == 2;
                  foreach (a[i])
                 a[i].size() == 2;}
  
  
  constraint c2 {
      
      foreach (a[i,j]) {
        a.sum() with (item.index(1) == i ? int'(item) : 0) == 10;
        a.sum() with (item.index(2) == j ? int'(item) : 0) == 10;
    }
      unique{a};
  }  
  
endclass

Error-[IAMC] Invalid array manipulation method call
testbench.sv, 18
Wrong usage of array manipulation method ‘sum’ as this method is not
supported on variable-size multidimensional arrays.

Error-[IAMC] Invalid array manipulation method call
testbench.sv, 19
Wrong usage of array manipulation method ‘sum’ as this method is not
supported on variable-size multidimensional arrays.

Can you please try and let me know if you are facing same issue.

Thanks,

In reply to jyothsna04:

The code you wrote and the code in the marked solution is illegal. The reduction methods only iterate over a single dimension of an array

  constraint c2 {
 
      foreach (a[i]) {
        a[i].sum() with (int'(item)) == 10;         // rows a[i][0] + a[i][1] 
        a.sum() with (int'(a[item.index][i]))== 10; // cols a[0][i] + a[1][i] 
    }
   //   unique{a};  // array size and sum too small to make unique
  }

In reply to dave_59:

Hi Dave,
The LRM does not specify any such restriction and the “solution” code was tested on a VCS simulator.
Thanks
Prasad.

In reply to jyothsna04:
The code you wrote and the code in the marked solution is illegal. The reduction methods only iterate over a single dimension of an array

  constraint c2 {
foreach (a[i]) {
a[i].sum() with (int'(item)) == 10;         // rows a[i][0] + a[i][1] 
a.sum() with (int'(a[item.index][i]))== 10; // cols a[0][i] + a[1][i] 
}
//   unique{a};  // array size and sum too small to make unique
}

In reply to prasadaddagarla:

The LRM only defines the behavior of all array manipulation for a single dimension. It even has this example

logic [7:0] m [2][2] = '{ '{5, 10}, '{15, 20} };
int y;
y = m.sum with (item.sum with (item)); // y becomes 50 => 5+10+15+20

Your tool seems to treat the array reduction methods differently inside a constraint versus outside a constraint. Try this code

class A;
  rand bit [4:0] a [3][3];
  constraint c1 {
    a.sum() == 15; // illegal
    a.sum() with (item.sum) == 15;
  }
endclass
          
module top;
  A h = new;
  initial begin
    assert (h.randomize);
    $display(h.a.sum());  // illegal
    $display(h.a.sum() with (item.sum));
  end
endmodule

In reply to dave_59:

Hi dave ,
Thanks for the solution. But I have doubts regarding col-sum.


 a.sum() with (int'(a[item.index][i]))== 10; // cols a[0][i] + a[1][i] 

-How is it working? what does item.index mean?

And what about diagonals? If I want to put constraints on the sum of values of diagonals How should I write the code?

In reply to Shubhabrata:

The array manipulation methods iterate over elements in one dimension of an array. item is each element that dimension and item.index is the value of the index for that item.

The default expression if you do not specify a with(expression) is just item, but you can replace it with what ever you want using the index as an iterator.

A diagonal would be

 a.sum() with (int'(a[item.index][item.index]))== 10;

In reply to dave_59:

Hi Dave, I tried below code and randomized 10 times. I am not able to understand the output here. what the a.sum value returning?

class A;
  rand bit [4:0] a [3][3];
  constraint c1 {
 //   a.sum() == 15; // illegal
  //  a.sum() with (item.sum) == 15;
  }
endclass
 
module top;
  A h = new;
  initial begin
    repeat(10) begin
    assert (h.randomize);
  //  $display(h.a.sum());  // illegal
    $display("a = %p", h.a);
    $display(h.a.sum() with (item.sum));
    end
  end
endmodule

below is the oupout

a = '{'{'h3, 'hf, 'h11}, '{'ha, 'h4, 'h13}, '{'h2, 'h9, 'h1e}} 
13
a = '{'{'h16, 'h17, 'h16}, '{'h11, 'h3, 'h1d}, '{'h1b, 'h1e, 'h18}} 
 5
a = '{'{'h1, 'h1e, 'h13}, '{'hc, 'h19, 'h12}, '{'hc, 'h14, 'hb}} 
20
a = '{'{'h9, 'hf, 'h15}, '{'h13, 'h17, 'ha}, '{'h1, 'h4, 'h9}} 
15
a = '{'{'hd, 'h1f, 'h18}, '{'h7, 'h18, 'h15}, '{'h1f, 'hc, 'hb}} 
14
a = '{'{'h7, 'h8, 'h1}, '{'h1, 'hc, 'h10}, '{'h4, 'h3, 'h1b}} 
15
a = '{'{'h10, 'h1, 'h7}, '{'h12, 'h7, 'h1c}, '{'h4, 'h17, 'h0}} 
 8
a = '{'{'h12, 'h15, 'h1a}, '{'h2, 'h11, 'h7}, '{'hb, 'h1b, 'h1a}} 
27
a = '{'{'h1d, 'hd, 'h1f}, '{'h9, 'h8, 'he}, '{'h11, 'h1, 'h1}} 
27
a = '{'{'h1a, 'h16, 'h18}, '{'h7, 'h17, 'h18}, '{'h1f, 'h7, 'h1d}} 
 1

In reply to Ramababu:

It is returning the sum as a truncated 5-bit unsigned value.
It would make more sense if it was written as

$display( h.a.sum(D1) with (D1.sum(D2) with (32'(D2))) );

In reply to dave_59:
I run the code below, but failed with meaasge “Identifier ‘D1’ has not been declared yet”, Why is it possible in the tb_top but not in the constraints c1?


class A;
  rand bit [4:0] a [3][3];
  constraint c1 {
  //      a.sum() with (item.sum()) == 15;
    a.sum(D1) with (D1.sum(D2) with (32'(D2))) == 9;
  }
endclass
 
module tb_top;
  A h = new;
  initial begin
    repeat(10) begin
    assert (h.randomize);
    $display("a = %p", h.a);
    //$display(h.a.sum(D1) with (D1.sum(D2) with (32'(D2))));
    end
  end
endmodule

In reply to jianfeng.he:

Hi,
You can try this way.


class total;
  rand bit [7:0] a [0:2][0:2];
  rand bit[7:0] s[3]; // 3 is the number of rows
  constraint c1 {foreach (a[i]) 
  {a[i].sum with(item>0?item:0)== s[i]; }
    s.sum with (item > 0 ?item:0) == 9;
                 unique{s};}
  function void display ();
                 foreach(a[i,j])
                 begin $write("%0d ",a[i][j]);if(j==2)$display();end
  endfunction
endclass
module test;
  total m1;
  initial begin
    m1=new ();
    m1.randomize();
    m1.display();
  end
endmodule

In reply to jianfeng.he:

The tool you are using is incorrectly iterating the sum() method differently in a constraint versus elsewhere.

This Mentor/Siemens EDA sponsored public forum is not for discussing tool specific usage or issues. Please read your tool’s user manual or contact your tool vendor directly for support.

i have int data[10][3]

and i have to write constraint like data[0][1]+data[1][1]+data[2][1]+…+data[10][1] == 20
how can i write constraint for this ??

class A ;
  rand int mem[3][3];
  constraint c1{ 
      	unique{mem}; 
    foreach(mem[i,j]) 
    {
      mem[i][j] inside {[1:9]}; 
    }
  };
    
  constraint c2{
    foreach(mem[i])
    {
      foreach(mem[k])
      {
        mem[i].sum() == mem[k].sum();
      } 
    }
  };
      
  constraint c3{
    foreach(mem[,j])
    {
      foreach(mem[,k])
      {
        mem.sum() with (mem[item.index][j]) == mem.sum() with (mem[item.index][k]);
      } 
    }
  };
endclass



module t();
  A a_h = new();
  initial begin
      a_h.randomize();
      $display("value is %p", a_h.mem); 
   end 
endmodule