Constraint solver issue, solves sometimes, doesn't solve most of the times results in errors

Question:

Array 1, Array 2, randomize them make sure all entries within array are unique. generate array1 and array2 such that at-least one element is common between two arrays.

variable 1 should take random value which is part of both arrays

For example

If array1 randomized to : '{12, 2, -2, 4, 6, 10, 1, 0}
If array2 randomized to : '{1, 5, 7, 12, 0, 20}

Then value1 should take random value inside {1, 12, 0} all with equal weight 33.33%

for simplicity you can take assumptions, for example array length will be random but max 10 elements etc etc

Solution:

class Card;
    rand int array1 [];
    rand int array2 [];
    rand int var1;
  
    int q [$];
    // To keep track of common entires across arrays
    rand int dummy[];
  
    // Unique
    constraint c_array1 {  
        array1.size() inside {[1:10]};
        unique{array1};
        foreach(array1[i])
            array1[i] inside {[-10:10]};
    };
    constraint c_array2 {  
        array2.size() inside {[1:10]};
        unique{array2};
        foreach(array2[i])
            array2[i] inside {[-10:10]};
    };
  
    // At-least one element is common between two arrays
    constraint c_common { 
      foreach(array1[i]) {
        foreach(array2[ii]){
          if (array1.size()>=array2.size()){
            dummy[i]==(array1[i]==array2[ii]);
          } else {
            dummy[ii]==(array1[i]==array2[ii]);          
          }
        }
      }
      dummy.size() == ((array1.size() >= array2.size()) ? array1.size() : array2.size()); 
      dummy.sum() > 0;
    };

    function void post_randomize ();
      foreach(array1[i])
        foreach(array2[ii])
          if (array1[i]==array2[ii])
            q.push_back(array1[i]);
      std::randomize(var1) with {var1 inside {q};};
    endfunction 

endclass

module tb;
  Card card; 

  initial begin
    repeat(5) begin
      card = new();
      card.randomize();
      $display("###############");
      $display ("# ARRAY1 is");
      foreach(card.array1[i])
        $display("%0d",card.array1[i]);
      $display("###############");
      $display ("# ARRAY2 is");
      foreach(card.array2[i])
        $display("%0d",card.array2[i]);  
      $display("###############");
      $display ("# DUMMY is");
      foreach(card.dummy[i])
        $display("%0d",card.dummy[i]);  
      $display("###############");    
      $display ("# Q is");
      foreach(card.q[i])
        $display("%0d",card.q[i]);
      $display("###############");    
      $display("# VAR1 is %0d #",card.var1);
      $display("###############\n\n\n");
    end
  end
endmodule

Issue:

Sometimes it solves the constraint and sometimes it does not (gives constraint solver errors).

1. When constraint solves, it generates valid output, for example:
###############

ARRAY1 is

2
###############

ARRAY2 is

2
-8
4
###############

DUMMY is

1
0
0
###############

Q is

2
###############

VAR1 is 2

###############

2. When constraint does not resolve, Full error is shown below:

=======================================================

Solver failed when solving following set of constraints

rand integer array1[0]; // rand_mode = ON
rand integer array1[1]; // rand_mode = ON
rand integer array1[2]; // rand_mode = ON
rand integer array1[3]; // rand_mode = ON
rand integer array1[4]; // rand_mode = ON
rand integer array1[5]; // rand_mode = ON
rand integer array1[6]; // rand_mode = ON
rand integer array1[7]; // rand_mode = ON
rand integer array1[8]; // rand_mode = ON
rand integer array1[9]; // rand_mode = ON
rand integer array2[0]; // rand_mode = ON
rand integer array2[1]; // rand_mode = ON
rand integer array2[2]; // rand_mode = ON
rand integer array2[3]; // rand_mode = ON
rand integer array2[4]; // rand_mode = ON
rand integer dummy[0]; // rand_mode = ON
rand integer dummy[1]; // rand_mode = ON
rand integer dummy[2]; // rand_mode = ON
rand integer dummy[3]; // rand_mode = ON
rand integer dummy[4]; // rand_mode = ON
rand integer dummy[5]; // rand_mode = ON
rand integer dummy[6]; // rand_mode = ON
rand integer dummy[7]; // rand_mode = ON
rand integer dummy[8]; // rand_mode = ON
rand integer dummy[9]; // rand_mode = ON

constraint c_array2 // (from this) (constraint_mode = ON) (testbench.sv:31)
{
unique {array2[0], array2[1], array2[2], array2[3], array2[4]};
}
constraint c_common // (from this) (constraint_mode = ON) (testbench.sv:39)
{
((32’((((((((((dummy[0] + dummy[1]) + dummy[2]) + dummy[3]) + dummy[4]) + dummy[5]) + dummy[6]) + dummy[7]) + dummy[8]) + dummy[9]))) > 0);
(dummy[0] == (array1[0] == array2[0]));
(dummy[0] == (array1[0] == array2[1]));
(dummy[1] == (array1[1] == array2[3]));
(dummy[1] == (array1[1] == array2[4]));
(dummy[2] == (array1[2] == array2[0]));
(dummy[2] == (array1[2] == array2[4]));
(dummy[3] == (array1[3] == array2[0]));
(dummy[3] == (array1[3] == array2[1]));
(dummy[4] == (array1[4] == array2[3]));
(dummy[4] == (array1[4] == array2[4]));
(dummy[5] == (array1[5] == array2[0]));
(dummy[5] == (array1[5] == array2[4]));
(dummy[6] == (array1[6] == array2[0]));
(dummy[6] == (array1[6] == array2[1]));
(dummy[7] == (array1[7] == array2[3]));
(dummy[7] == (array1[7] == array2[4]));
(dummy[8] == (array1[8] == array2[0]));
(dummy[8] == (array1[8] == array2[4]));
(dummy[9] == (array1[9] == array2[0]));
(dummy[9] == (array1[9] == array2[1]));
}

=======================================================

Info-[CNST-SATE] A standalone test-case for this failure has automatically been extracted
from randomize serial 1 partition 2.
To reproduce the error using the extracted testcase, please use the
following command:
cd /home/runner/./simv.cst/testcases;
vcs -sverilog extracted_r_1_p_2_inconsistent_constraints.sv -R
To reproduce the error using the original design and verbose logging, re-run
simulation using:
simv +ntb_solver_debug=trace +ntb_solver_debug_filter=1
To reproduce the error using the original design and debug the error with
Verdi/DVE:

  1. re-compile the original design with -debug_access+all, if not already
    done so
    % vcs -debug_access+all
  2. re-run the simulation interactively with -gui/-verdi
    % simv -gui/-verdi
  3. enter the following commands to begin interactive constraint
    inconsistency debug within Verdi/DVE
    I. set the breakpoint: verdi/dve> stop -solver -serial 1
    II. run the simulation till it stops: verdi/dve> run
    III. step in the constraint solver: verdi/dve> step -solver

Error-[CNST-CIF] Constraints inconsistency failure
testbench.sv, 69
Constraints are inconsistent and cannot be solved.
Please check the inconsistent constraints being printed above and rewrite
them.

Tool:

Additional question:

Funny thing is if I replace c_array# constraint code:

        foreach(array#[i])
            array#[i] inside {[-10:10]};

with

        foreach(array#[i])
            array#[i] inside {[0:10]};

Then simulator just hangs forever, no errors no displays.

NOTE:
I am more interested on why this logic does not work, rather than alternative solutions. Thank you.

In reply to pribhi95:

I think I know what is the issue in above code with help from friend and looking at errors more closely, following logic I tried replacing:

 
    rand bit dummy[];   
    // At-least one element is common between two arrays
    constraint c_common { 
      foreach(array1[i]) {
        foreach(array2[ii]){
          if (array1.size()>=array2.size()){
            dummy[ii] == (dummy[ii] | (array1[i]==array2[ii]));
          } else {
            dummy[i] == (dummy[i] | (array1[i]==array2[ii]));          
          }
        }
      }
      dummy.size() == ((array1.size() >= array2.size()) ? array2.size() : array1.size()); 
      int'(dummy.sum()) > 0;
    };

At least I was able to resolve constraint error for dummy, Although, this won’t ensure that we get at-least 1 value common between two arrays, as dummy itself is random and that comes up with rand value and gets ORed, we will be prone to get extra elements set to 1 due to this. We need yet a way to initialize dummy to 0 to start with.

May be this can’t be solved this way,

Instead I should first decide how many elements I want to keep common between array (random number between 1 and min size of either array), then copy over in constraint from one array to the other and in post randomize shuffle both arrays.

**FINAL solution:
**


class Card;
    rand int array1 [];
    rand int array2 [];
    rand int var1;
  
    int q [$];
    rand int common_entries;
  
    // Unique
    constraint c_array1 {  
      array1.size() inside {[1:10]};
      unique{array1};
      foreach(array1[i])
        array1[i] inside {[-10:10]};
    };
    constraint c_array2 {  
      array2.size() inside {[1:10]};
      unique{array2};     
      foreach(array2[i])
        array2[i] inside {[-10:10]};
    };
  
    constraint c_common { 
      common_entries inside {[1:((array1.size() >= array2.size()) ? array2.size() : array1.size())]};
      foreach(array1[i])
        if (i<common_entries)
          array1[i] == array2[i];
    };

    function void post_randomize ();
      foreach(array1[i])
        foreach(array2[ii])
          if (array1[i]==array2[ii])
            q.push_back(array1[i]);
      array1.shuffle();
      array2.shuffle();
      std::randomize(var1) with {var1 inside {q};};
    endfunction 

endclass

module tb;
  Card card; 

  initial begin
    repeat(10) begin
      card = new();
      card.randomize();
      $display("###############");
      $display ("# ARRAY1 is");
      foreach(card.array1[i])
        $display("%0d",card.array1[i]);
      $display("###############");
      $display ("# ARRAY2 is");
      foreach(card.array2[i])
        $display("%0d",card.array2[i]);    
      $display("###############");    
      $display ("# Q is");
      foreach(card.q[i])
        $display("%0d",card.q[i]);
      $display("###############");    
      $display("# VAR1 is %0d #",card.var1);
      $display("###############\n\n\n");
    end
  end
endmodule