File Coverage

blib/lib/Math/Telephony/ErlangC.pm
Criterion Covered Total %
statement 132 170 77.6
branch 124 158 78.4
condition 12 15 80.0
subroutine 26 33 78.7
pod 14 14 100.0
total 308 390 78.9


line stmt bran cond sub pod time code
1             package Math::Telephony::ErlangC;
2              
3 2     2   106506 use version; our $VERSION = qv('1.0.2');
  2         7517  
  2         12  
4              
5 2     2   184 use warnings;
  2         5  
  2         67  
6 2     2   10 use strict;
  2         9  
  2         52  
7 2     2   11 use Carp;
  2         3  
  2         303  
8 2     2   1947 use English qw( -no_match_vars );
  2         26271  
  2         14  
9              
10 2     2   1200 use base 'Exporter';
  2         14  
  2         433  
11             our %EXPORT_TAGS = (
12             'all' => [
13             qw(
14             wait_probability servers_waitprob traffic_waitprob
15             maxtime_probability servers_maxtime traffic_maxtime
16             service_time_maxtime service_time2_maxtime max_time_maxtime
17             average_wait_time servers_waittime traffic_waittime
18             service_time_waittime service_time2_waittime
19             )
20             ]
21             );
22             our @EXPORT_OK = (@{$EXPORT_TAGS{'all'}});
23             our @EXPORT = qw();
24              
25 2     2   2312 use Math::Telephony::ErlangB;
  2         7943  
  2         6129  
26              
27             # Module implementation here
28             {
29             my %validators = (
30             traffic => sub { defined($_[0]) && $_[0] >= 0 },
31             servers =>
32             sub { defined($_[0]) && $_[0] >= 0 && $_[0] == int($_[0]) },
33             probability => sub { defined($_[0]) && $_[0] >= 0 && $_[0] <= 1 },
34             time => sub { defined($_[0]) && $_[0] >= 0 },
35             precision => sub { !defined($_[0]) || ($_[0] > 0) },
36             );
37              
38             sub _validate {
39 123186     123186   251760 while (@_) {
40 215529         303238 my $type = shift;
41 215529         248790 my $value = shift;
42 215529 100       429047 return undef unless $validators{$type}($value);
43             }
44 4064         8987 return 1;
45             } ## end sub _validate
46             }
47              
48             sub _cross {
49 0     0   0 my ($asc, $desc, $v_begin, $v_end, $prec) = @_;
50 0 0       0 return ($v_begin + $v_end) / 2 if ($v_end - $v_begin) < $prec;
51              
52 0         0 my $v;
53 0         0 my $diff = $prec;
54 0         0 while ($v_end - $v_begin >= $prec) {
55 0         0 $v = ($v_begin + $v_end) / 2;
56 0         0 my $d = $desc->($v);
57 0         0 my $a = $asc->($v);
58 0         0 $diff = $desc->($v) - $asc->($v);
59 0 0       0 if ($diff > 0) { $v_begin = $v }
  0         0  
60 0         0 else { $v_end = $v }
61             } ## end while ($v_end - $v_begin ...
62 0         0 return ($v_begin + $v_end) / 2;
63             } ## end sub _cross
64              
65             ##########################################################################
66             sub wait_probability {
67 122     122 1 3884 my ($traffic, $servers) = @_;
68 122         283 my $bprob =
69             Math::Telephony::ErlangB::blocking_probability($traffic, $servers);
70 122 100       2025 return undef unless defined $bprob;
71 66 100 100     278 return $bprob if $bprob == 0 || $bprob == 1;
72              
73 58         140 return $bprob / (1 - (1 - $bprob) * $traffic / $servers);
74             } ## end sub wait_probability
75              
76             sub servers_waitprob {
77 96     96 1 9262 my ($traffic, $wait_probability) = @_;
78             return undef
79 96 100       177 unless _validate(
80             traffic => $traffic,
81             probability => $wait_probability
82             );
83 14 100       41 return 0 unless $traffic > 0;
84 5 50       12 return undef unless $wait_probability > 0;
85 5 100       16 return 0 unless $wait_probability < 1;
86              
87             Math::Telephony::ErlangB::_generic_servers(
88             sub {
89 1     1   8 my $v = wait_probability($traffic, $_[0]);
90 1   33     23 return defined $v && $v > $wait_probability;
91             }
92 1         10 );
93             } ## end sub servers_waitprob
94              
95             sub traffic_waitprob {
96 753     753 1 19711 my ($servers, $wait_probability, $prec) = @_;
97             return undef
98 753 100       1364 unless _validate(
99             servers => $servers,
100             probability => $wait_probability,
101             precision => $prec,
102             );
103 49 100       130 return 0 unless $servers > 0;
104 19 100       45 return 0 unless $wait_probability > 0;
105 10 100       29 return undef unless $wait_probability < 1;
106              
107 1 50       4 $prec = $Math::Telephony::ErlangB::default_precision
108             unless defined $prec;
109              
110             Math::Telephony::ErlangB::_generic_traffic(
111             sub {
112 15     15   109 my $v = wait_probability($_[0], $servers);
113 15   66     69 return defined $v && $v < $wait_probability;
114             },
115 1         7 $prec,
116             $servers
117             );
118             } ## end sub traffic_waitprob
119              
120             ##########################################################################
121             sub maxtime_probability {
122 6989     6989 1 151906 my ($traffic, $servers, $mst, $maxtime) = @_;
123             return undef
124 6989 100       15093 unless _validate(
125             traffic => $traffic,
126             servers => $servers,
127             time => $mst,
128             time => $maxtime,
129             );
130 333 100       687 return 1 unless $traffic;
131 233 100       483 return 0 unless $servers;
132 133 100       276 return 1 unless $mst;
133 73 100       194 return 0 unless $maxtime;
134 25 100       52 return undef unless $servers > $traffic;
135              
136 19         33 my $wprob = wait_probability($traffic, $servers);
137 19 50       38 return undef unless defined $wprob;
138              
139 19         76 return 1 - $wprob * exp(-($servers - $traffic) * $maxtime / $mst);
140             } ## end sub maxtime_probability
141              
142             sub servers_maxtime {
143 11223     11223 1 223430 my ($traffic, $maxtime_probability, $mst, $maxtime) = @_;
144             return undef
145 11223 100       20391 unless _validate(
146             traffic => $traffic,
147             probability => $maxtime_probability,
148             time => $mst,
149             time => $maxtime,
150             );
151 599 100       1726 return 0 unless $traffic > 0;
152 374 100       1090 return 1 unless $mst > 0;
153 194 100       443 return undef unless $maxtime_probability > 0;
154 114 100       661 return undef unless $maxtime > 0;
155              
156             Math::Telephony::ErlangB::_generic_servers(
157             sub {
158 13     13   67 my $v = maxtime_probability($traffic, $_[0], $mst, $maxtime);
159 13 100       36 return 1 unless defined $v;
160 8         23 return $v < $maxtime_probability;
161             }
162 2         15 );
163             } ## end sub servers_maxtime
164              
165             sub traffic_maxtime {
166 73479     73479 1 1554661 my ($servers, $maxtime_probability, $mst, $maxtime, $prec) = @_;
167             return undef
168 73479 100       138590 unless _validate(
169             servers => $servers,
170             probability => $maxtime_probability,
171             time => $mst,
172             time => $maxtime,
173             precision => $prec,
174             );
175 1543 100       7172 return 0 unless $servers > 0;
176 793 100       1692 return 0 unless $maxtime_probability > 0;
177 568 100       1388 return undef unless $mst > 0;
178 253 100       748 return undef unless $maxtime > 0;
179              
180 1 50       5 $prec = $Math::Telephony::ErlangB::default_precision
181             unless defined $prec;
182              
183             Math::Telephony::ErlangB::_generic_traffic(
184             sub {
185 11     11   82 my $v = maxtime_probability($_[0], $servers, $mst, $maxtime);
186 11   100     57 return defined $v && $v > $maxtime_probability;
187             },
188 1         7 $prec,
189             $servers
190             );
191             } ## end sub traffic_maxtime
192              
193             sub service_time_maxtime {
194 12085     12085 1 245250 my ($traffic, $servers, $mprob, $maxtime) = @_;
195             return undef
196 12085 100       22894 unless _validate(
197             traffic => $traffic,
198             servers => $servers,
199             probability => $mprob,
200             time => $maxtime,
201             );
202 565 100       1384 return 0 unless $traffic > 0;
203 385 100       852 return undef unless $servers > 0;
204 205 100       445 return 0 unless $mprob > 0;
205 145 100       355 return undef unless $mprob < 1;
206 85 100       290 return 0 unless $maxtime > 0;
207 1 50       16 return undef unless $servers > $traffic;
208              
209             # Input already _validated, use private "fast" function
210 1         3 my $wprob = wait_probability($traffic, $servers);
211              
212 1         30 return -($servers - $traffic) * $maxtime / log((1 - $mprob) / $wprob);
213             } ## end sub service_time_maxtime
214              
215             sub service_time2_maxtime {
216 0     0 1 0 my ($frequency, $servers, $mprob, $maxtime, $prec) = @_;
217             return undef
218 0 0       0 unless _validate(
219             traffic => $frequency, # Validate like a traffic
220             servers => $servers,
221             probability => $mprob,
222             time => $maxtime,
223             );
224 0 0       0 return 0 unless $frequency > 0;
225 0 0       0 return undef unless $servers > 0;
226 0 0       0 return 0 unless $mprob > 0;
227 0 0       0 return undef unless $mprob < 1;
228 0 0       0 return 0 unless $maxtime > 0;
229              
230 0 0       0 $prec = $Math::Telephony::ErlangB::default_precision
231             unless defined $prec;
232              
233 0         0 my $theLog = log(1 - $mprob);
234 0         0 my $lambdaTm = $frequency * $maxtime;
235             my $traffic = _cross(
236 0     0   0 sub { log(wait_probability($_[0], $servers)) },
237 0     0   0 sub { $theLog + $lambdaTm * ($servers - $_[0]) / $_[0] },
238 0         0 $servers * $lambdaTm / ($lambdaTm - $theLog),
239             $servers,
240             $prec * $frequency # Adjusted precision for traffic domain
241             );
242 0         0 return $traffic / $frequency;
243             } ## end sub service_time2_maxtime
244              
245             sub max_time_maxtime {
246 12113     12113 1 227401 my ($traffic, $servers, $mprob, $mst) = @_;
247             return undef
248 12113 100       24439 unless _validate(
249             traffic => $traffic,
250             servers => $servers,
251             probability => $mprob,
252             time => $mst,
253             );
254 593 100       1526 return 0 unless $traffic > 0;
255 413 100       1041 return undef unless $servers > 0;
256 233 100       615 return 0 unless $mst;
257 125 100       329 return 0 unless $mprob > 0;
258 77 100       217 return undef unless $mprob < 1;
259 29 100       100 return undef unless $servers > $traffic;
260              
261 1         3 my $wprob = wait_probability($traffic, $servers);
262              
263 1         8 return -$mst / (log((1 - $mprob) / $wprob) * ($servers - $traffic));
264             } ## end sub max_time_maxtime
265              
266             ##########################################################################
267             sub average_wait_time {
268 722     722 1 19432 my ($traffic, $servers, $mst) = @_;
269             return undef
270 722 100       1234 unless _validate(
271             traffic => $traffic,
272             servers => $servers,
273             time => $mst,
274             );
275 82 100       191 return 0 unless $traffic > 0;
276 62 100       144 return undef unless $servers > 0;
277 42 100       98 return 0 unless $mst > 0;
278 30 100       68 return undef unless ($servers > $traffic);
279              
280             # Use private calculation function, input already _validated
281 19         33 my $wprob = wait_probability($traffic, $servers);
282              
283 19         50 return $wprob * $mst / ($servers - $traffic);
284             } ## end sub average_wait_time
285              
286             sub servers_waittime {
287 639     639 1 18786 my ($traffic, $average_wait_time, $mst) = @_;
288              
289             return undef
290 639 100       1051 unless _validate(
291             traffic => $traffic,
292             time => $average_wait_time,
293             time => $mst,
294             );
295 63 100       187 return 0 unless $traffic > 0;
296 38 100       115 return 1 unless $mst > 0;
297 18 100       63 return undef unless $average_wait_time > 0;
298              
299             Math::Telephony::ErlangB::_generic_servers(
300             sub {
301 14     14   76 my $v = average_wait_time($traffic, $_[0], $mst);
302 14 100       37 return 1 unless defined $v;
303 8         20 return $v > $average_wait_time;
304             }
305 2         18 );
306             } ## end sub servers_waittime
307              
308             sub traffic_waittime {
309 4390     4390 1 105036 my ($servers, $average_wait_time, $mst, $prec) = @_;
310             return undef
311 4390 100       8570 unless _validate(
312             servers => $servers,
313             time => $average_wait_time,
314             time => $mst,
315             precision => $prec,
316             );
317 166 100       426 return 0 unless $servers > 0;
318 91 100       240 return undef unless $average_wait_time > 0;
319 37 100       130 return undef unless $mst > 0;
320              
321 1 50       4 $prec = $Math::Telephony::ErlangB::default_precision
322             unless defined $prec;
323              
324             Math::Telephony::ErlangB::_generic_traffic(
325             sub {
326 11     11   73 my $v = average_wait_time($_[0], $servers, $mst);
327 11   100     52 return defined $v && $v < $average_wait_time;
328             },
329 1         8 $prec,
330             $servers
331             );
332             } ## end sub traffic_waittime
333              
334             sub service_time_waittime {
335 697     697 1 19589 my ($traffic, $servers, $awt) = @_;
336             return undef
337 697 100       1896 unless _validate(
338             traffic => $traffic,
339             servers => $servers,
340             time => $awt,
341             );
342 57 100       319 return 0 unless $traffic > 0;
343 37 100       97 return undef unless $servers > 0;
344 17 100       53 return 0 unless $awt > 0;
345 5 100       22 return undef unless ($servers > $traffic);
346              
347 1         3 my $bprob = wait_probability($traffic, $servers);
348              
349 1         6 return $awt * ($servers - $traffic) / $bprob;
350             } ## end sub service_time_waittime
351              
352             sub service_time2_waittime {
353 0     0 1   my ($frequency, $servers, $awt, $prec) = @_;
354             return undef
355 0 0         unless _validate(
356             traffic => $frequency, # Validate exactly as a traffic
357             servers => $servers,
358             time => $awt,
359             precision => $prec,
360             );
361 0 0         return undef unless $frequency > 0; # No calls...
362 0 0         return undef unless $servers > 0;
363 0 0         return 0 unless $awt > 0;
364              
365 0 0         $prec = $Math::Telephony::ErlangB::default_precision
366             unless defined $prec;
367              
368 0           my $lambdaTa = $frequency * $awt;
369             my $traffic = _cross(
370 0     0     sub { wait_probability($_[0], $servers) }, # Ascending
371 0     0     sub { $lambdaTa * ($servers / $_[0] - 1) }, # Descending
372 0           $servers * $lambdaTa / (1 + $lambdaTa), $servers,
373             $prec * $frequency
374             );
375 0           return $traffic / $frequency;
376             } ## end sub service_time2_waittime
377              
378             1; # Magic true value required at end of module
379             __END__