File Coverage

blib/lib/Random/Skew/Test.pm
Criterion Covered Total %
statement 87 100 87.0
branch 30 42 71.4
condition 12 16 75.0
subroutine 7 7 100.0
pod 0 4 0.0
total 136 169 80.4


line stmt bran cond sub pod time code
1             package Random::Skew::Test;
2              
3 1     1   72779 use strict;
  1         2  
  1         31  
4 1     1   9 use warnings;
  1         2  
  1         37  
5              
6             our $VERSION = '0.02';
7              
8 1     1   2711 use Random::Skew;
  1         1141  
  1         995  
9              
10             sub sample {
11              
12 2     2 0 1728 my $self = shift;
13 2         11 my %params = @_;
14              
15 2         3 my @bad;
16              
17 2 50       8 my $iter = $params{iter} or push @bad,"Random::Skew::sample(iter=>?) parameter missing";
18 2 50       6 my $skew = $params{skew} or push @bad,"Random::Skew::sample(skew=>{}) parameter missing";
19 2   50     6 my $grain= $params{grain} // [ qw/25 250 1000/ ];
20 2   50     6 my $round= $params{round} // [ qw/0 .5/ ];
21              
22 2 50       5 die @bad if @bad;
23              
24 2         5 my @output;
25              
26             my $rs;
27              
28 2         5 my @grain = @$grain;
29 2         4 my @round = @$round;
30              
31 2         5 foreach $grain ( @grain ) {
32              
33 3         5 $Random::Skew::GRAIN = $grain;
34 3         7 my @r = @round;
35              
36 3         7 while ( @r ) {
37 4         8 $round = shift @r;
38              
39 4         6 $Random::Skew::ROUNDING = $round;
40              
41 4         34 $rs = Random::Skew->new( %$skew );
42 4         490 my $pop = $rs->{_pop};
43              
44 4 100       10 if ( $rs->{_tot} < $rs->{_grain} ) {
45 2         4 $round = '[moot at this grain]';
46 2         5 @r = ();
47             }
48              
49 4         19 push @output, "Grain=$Random::Skew::GRAIN (Rounding=+$round): -=-=-=-=-=-=-=-=-=-\n",
50             &show( $rs ),
51             &run( $rs, $iter );
52              
53             }
54              
55             }
56              
57 2         27 return @output,
58             "Typically you want the Ratio column to be close to 1.0 (0.9ish to 1.1ish).\n",
59             "However, more iterations (>$iter) might smooth out the results.\n\n";
60              
61             }
62              
63              
64              
65             # To see the structure of a Random::Skew object
66             sub show {
67 6     6 0 11 my $set = shift;
68 6   100     19 my $indent = shift || '';
69              
70 6         14 my @output;
71              
72             my %v;
73 6         0 my $v;
74 6         9 foreach $v ( @{ $set->{_set} } ) {
  6         14  
75 130 100       218 $v{ $v }++ unless ref $v;
76             }
77 6 50       47 foreach $v ( sort {$v{$b} <=> $v{$a} or $a cmp $b} keys %v ) {
  11         34  
78 14 50       49 push @output, "$indent$v\t$v{$v}\n"
79             if $v; # no need to show empties, _fraction handles those anyway
80             }
81              
82 6 100       21 if ( $set->{_fraction} ) {
83             push @output,
84             "$indent...and smaller (when rand(0..$set->{_pop}) < $set->{_fraction}):\n",
85 2         24 &show( $set->{_set}[0], "$indent " );
86             }
87              
88 6         26 return @output;
89             }
90              
91              
92              
93             sub run {
94 4     4 0 9 my $rs = shift;
95 4   50     29 my $ct = shift // 1_000_000;
96              
97 4         10 my @output;
98              
99 4         11 push @output, "--${ct}x:\n",
100             "Bucket\tReturned(%)\tRequested(%)\tRatio\n",
101             "======\t========\t=========\t=====\n";
102              
103 4         8 my %result;
104 4         13 while ( $ct-- > 0 ) {
105              
106             # _/_/_/_/ _/_/_/_/ _/_/_/_/ _/_/_/_/
107             # _/ _/ _/ _/
108             # _/ _/_/_/ _/_/_/ _/
109             # _/ _/ _/ _/
110             #_/ _/_/_/_/ _/_/_/_/ _/
111              
112 301         3957 $result{ $rs->item }++; # Here's where we iterate thru the tests
113              
114             }
115              
116 4         51 my $overall_prd = 1.0;
117 4         5 my $is_zero = 0;
118 4         5 my $overall_avg = 0.0;
119              
120 4         8 my $p = $rs->{_params};
121 4         5 my $p_tot = 0;
122 4         4 my $r_tot = 0;
123 4         14 foreach my $item ( keys %$p ) {
124 14   50     25 $p_tot += $p->{ $item } // 0;
125 14   100     32 $r_tot += $result{ $item } // 0;
126             }
127 4 50       15 foreach my $item ( sort {$p->{$b} <=> $p->{$a} or $a cmp $b } keys %$p ) {
  13         31  
128 14         27 my $p_pct = 100 * $p->{ $item } / $p_tot;
129 14   100     41 my $r_pct = 100 * ($result{ $item } // 0) / $r_tot;
130 14         28 my $ratio = $r_pct / $p_pct;
131 14 100       28 $is_zero ++ unless defined( $result{ $item } );
132              
133 14         19 my $ratio_alert = '';
134 14 100       28 $ratio_alert = ' <-- low?' if $ratio < 9/10;
135 14 100       28 $ratio_alert = ' <-- LOW?' if $ratio < 8/10;
136 14 100       24 $ratio_alert = ' <-- high?' if $ratio > 10/9;
137 14 100       24 $ratio_alert = ' <-- HIGH?' if $ratio > 10/8;
138             push @output, sprintf "%s:\t%s (%3.3g)\t%s (%3.3g)\t%.4f%s\n",
139             $item,
140             &h( $result{$item} // 0 ), $r_pct,
141 14   100     36 &h( $p->{$item} ), $p_pct,
142             $ratio, $ratio_alert,
143             ;
144 14         28 $overall_prd *= $ratio;
145 14         24 $overall_avg += $ratio;
146             }
147 4         10 $overall_avg /= scalar keys %$p;
148 4 50       12 if ( $is_zero > 1 ) {
    100          
149 0         0 push @output, "Note: there are $is_zero buckets not represented (which causes zero product).\n";
150             } elsif ( $is_zero > 0 ) {
151 3         6 push @output, "Note: there is a bucket not represented (which causes zero product).\n";
152             }
153 4         21 push @output, sprintf "Overall ratio product: %5.5g\nOverall ratio average: %5.5g\n\n",
154             $overall_prd,
155             $overall_avg;
156              
157 4         30 return @output;
158             }
159              
160              
161              
162             sub h {
163 28     28 0 42 my $v = shift;
164 28         36 my $unit = '';
165 28         33 my $div = 1;
166 28         35 my $fmt = '%.0f'; # %f rounds, %d truncates
167 28 50       84 if ( $v > 2_000_000_000 ) {
    50          
    50          
    50          
    50          
168 0         0 $div = 1000 * 1000 * 1000;
169 0         0 $unit = 'g';
170             } elsif ( $v > 9_999_999 ) {
171 0         0 $div = 1000 * 1000;
172 0         0 $unit = 'm';
173             } elsif ( $v > 2_000_000 ) {
174 0         0 $div = 1000 * 1000;
175 0         0 $unit = 'm';
176 0         0 $fmt = '%.1f';
177             } elsif ( $v > 9_999 ) {
178 0         0 $div = 1000;
179 0         0 $unit = 'k';
180             } elsif ( $v > 2_000 ) {
181 0         0 $div = 1000;
182 0         0 $unit = 'k';
183 0         0 $fmt = '%.1f';
184             }
185 28         180 return sprintf "$fmt%s", $v/$div, $unit;
186             }
187              
188              
189              
190             1;
191             __END__