Queue randomization distribution

QUESTION:
Create a system verilog class with a random queue constrained with the following conditions:
1)It should have a random number of elements between 1 and 32
2)All the elements should have a value between 0 and 31
3)All the elements should be different
4)There should be a 30% probability of the elements to be in order(ascending or descending)
5)10% of the time it should be the smallest possible queue
6)10% of the time it should be the biggest possible queue
7)80% of the time should be equally distributed among the other possible sizes s

MY LOGIC:


class abc;
  rand int q[$];
  constraint c1 {foreach(q[i]) q[i] inside {[0:31]};}
  constraint c2 {q.size dist {1:=10, 31:=10, [2:30]:=80};}
  constraint c3 {unique {q};}

  constraint c5 {foreach(q[i]) {
                 if (i>0) {q[i] dist {(q[i]>q[i-1]) := 30, q[i] := 70};}}
                }
endclass

module exp;
  abc a = new;
  initial begin 
    repeat (10) begin 
    a.randomize();
    $display ("### %p ###", a.q);
    end 
  end 
endmodule


ACTUAL OUTPUT:

'{20, 10, 11, 6, 3, 7, 18, 23, 4, 26, 15, 9, 31, 19, 25, 14, 13, 2, 5, 28, 12, 16, 29, 30, 0, 1, 24, 22}

'{31, 19, 22, 29, 17, 23, 4, 8, 3, 11, 18, 21, 0, 1, 9, 7, 16, 28, 2, 24, 20, 10, 26, 5, 12, 15}

'{29, 26, 24, 5, 8, 1, 15, 19, 16, 27, 11, 23, 25, 10, 7, 9, 30, 0, 28, 2, 13, 31, 20, 4, 3, 6, 17, 12}

'{4, 3, 25, 26, 23, 17, 13, 14, 24, 6, 0, 1, 29, 5, 27, 2, 19, 11, 18, 8, 12, 7, 10, 20, 15}

'{22, 28, 10, 23, 13, 0, 1, 29, 7, 14, 26, 21}

'{29, 1, 18, 15, 5, 13, 31, 28, 27, 6, 26, 11, 2, 30, 20, 14, 12, 17, 0, 4, 23}

'{3, 20, 0, 1, 25, 10, 17, 24, 16, 22, 21, 29, 15, 28, 11, 9, 4, 26, 2, 7, 6, 19, 18, 27}

'{3, 23, 30, 1, 14, 5, 8, 15, 19, 26, 29, 28, 12, 7, 0, 4, 10, 9, 13}

'{5, 0, 1, 23, 8, 11, 19, 18, 28, 29, 15, 10, 22}

'{15, 0, 27, 28, 19, 21, 1, 9}


EXPECTED OUTPUT:
I only want 3 out of 10 elements to be sorted either ascending or descending and the remaining elements to be randomized.

constraint c5 is not fulfilling the requirement of 30% probability of the elements to be in order. Any input would help.

In reply to sk7799:
You have a misunderstanding about how the dist works in constraint c5. See the reply to a recent question.

You should create a separate random mode variable so that the ordering is consistent across the array

class abc;
  rand int q[$];
  rand enum {unordered_,ascending_,descending} ordering;
  constraint c1 {foreach(q[i]) q[i] inside {[0:31]};}
  constraint c2 {q.size dist {1:=10, 31:=10, [2:30]:/80};} // use :/ with a range
  constraint c3 {unique {q};}
  constraint c5 {
    ordering dist {[ascending_:descending]:/30, unordered_:=70};
    ordering == ascending_ -> foreach(q[i]) i>0 -> q[i-1] < q[i];
    ordering == descending -> foreach(q[i]) i>0 -> q[i-1] > q[i];
  }
endclass
 
module exp;
  abc a = new;
  initial begin 
    repeat (50) begin 
      assert(a.randomize());
      $display ("%s ### %p ###", a.ordering.name, a.q);
    end 
  end 
endmodule

In reply to dave_59:

Hi Dave,

Thank you for your response.

I have one question though after looking into the link you have provided: here for my question, nothing is mentioned for unordered. How will the constraint interpret that as. The constraint says unordered 70% but how will the constraint know what unordered is.
Please let me know.

Thank you.

In reply to sk7799:

I interpreted “unordered” to mean “no constraint to be ordered” since there is no such thing as 1 or 2 element array without an ordering. If you want, you could add another constraint that says: if unordered and the size is greater than 2, then the elements must be out of order. I’ll leave that up to you to figure out. I can give you a hint not use the foreach construct for that.

In reply to dave_59:

Hi Dave,
Thank You for your response.
I understood not to use foreach but how can I tell randomization not to do something. I’m unable to get to that logic.
Can I just use q[i] as it is. Will that just put the remaining unordered elements as they come.
Also I’m curious how the randomization interprets if I do not specify any condition for the unordered.
Please let me know.
Thanks.

In reply to sk7799:

The problem with taking the unconstrained elements as they come is the for small sizes of q, there is a high probability of getting the elements in numerical order (q.size–3, 33% chance). That skews your desired probability of unordered to be 70%.

You tell the constraint solver to do or not something by putting it in terms of an equation that that must be true. I can convert the foreach loops to an array reduction and() method, and use the logical equivalence operator. This operator returns true of both LHS and RHS or both true or both false.

class abc;
  rand int q[$];
  rand enum {unordered_,ascending_,descending} ordering;
  constraint c1 {foreach(q[i]) q[i] inside {[0:31]};}
  constraint c2 {q.size dist {1:=10, 31:=10, [2:30]:/80};} // use :/ with a range
  constraint c3 {unique {q};}
  constraint c5 {
    ordering dist {[ascending_:descending]:/30, unordered_:=70};
    q.size() > 2 -> {
      ordering == ascending_ <-> q.and() with (item.index == 0 || 
                                               q[item.index-1] < item);
      ordering == descending <-> q.and() with (item.index == 0 || 
                                               q[item.index-1] > item);
    }
  }
endclass