-
-
Save henrikbjorn/be3fc3555609e14deaacec763532ff32 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var MAX_AGENTS_TO_TEST = 200; | |
function determineAgents(callDuration, calls, periodLength, answerTarget, serviceLevelTarget) { | |
if(calls === 0) return(0); | |
for (var agents = 1; agents <= MAX_AGENTS_TO_TEST; agents++) { | |
if(serviceLevel(callDuration, calls, periodLength, agents, answerTarget) >= serviceLevelTarget) break; | |
} | |
return(agents); | |
} | |
function serviceLevel(callDuration, calls, periodLength, agents, answerTarget) { | |
var U = callDuration * calls / periodLength; | |
var o = U / agents; | |
var ec = PoissonTerm(U, agents)/(PoissonTerm(U, agents) + (1-o)*PoissonP(U,agents-1)); | |
return(1 - ec * Math.exp(-(agents-U)*answerTarget/callDuration)); | |
} | |
// Helper functions | |
function g( x ) { | |
// Peizer & Pratt 1968, JASA 63: 1416-1456 | |
var switchlev = 0.1, z; | |
if (x == 0) z = 1; | |
else | |
if (x == 1) z = 0; | |
else { | |
var d = 1 - x; | |
if (Math.abs(d) > switchlev) | |
z = (1 - (x * x) + (2 * x * Math.log(x))) / (d * d); | |
else { | |
z = d / 3; // first term | |
var di = d; // d**1 | |
for (var i = 2; i <= 7; i++) { | |
di *= d; // d**i | |
z += (2 * di) / ((i+1) * (i+2)); | |
} | |
} | |
} | |
return z; | |
} | |
function NormalP( x ) { | |
// Abramowitz & Stegun 26.2.19 | |
var | |
d1 = 0.0498673470, | |
d2 = 0.0211410061, | |
d3 = 0.0032776263, | |
d4 = 0.0000380036, | |
d5 = 0.0000488906, | |
d6 = 0.0000053830, | |
a = Math.abs(x), | |
t; | |
t = 1.0 + a*(d1+a*(d2+a*(d3+a*(d4+a*(d5+a*d6))))); | |
// to 16th power | |
t *= t; t *= t; t *= t; t *= t; | |
t = 1.0 / (t+t); // the MINUS 16th | |
if (x >= 0) t = 1-t; | |
return t; | |
} | |
function LnFact( x ) { | |
// ln(x!) by Stirling's formula | |
// see Knuth I: 111 | |
if (x <= 1) x = 1; | |
if (x < 12) | |
return Math.log( Fact(Math.round(x)) ); | |
else { | |
var invx = 1 / x; | |
var invx2 = invx * invx; | |
var invx3 = invx2 * invx; | |
var invx5 = invx3 * invx2; | |
var invx7 = invx5 * invx2; | |
var sum = ((x + 0.5) * Math.log(x)) - x; | |
sum += Math.log(2*Math.PI) / 2; | |
sum += (invx / 12) - (invx3 / 360); | |
sum += (invx5 / 1260) - (invx7 / 1680); | |
return sum; | |
} | |
} | |
function Fact( x ) { | |
// x factorial | |
var t=1; | |
while (x > 1) | |
t *= x--; | |
return t; | |
} | |
function PoissonPD( u, k ) { | |
// Peizer & Pratt 1968, JASA 63: 1416-1456 | |
var s = k + (1/2); | |
var d1 = k + (2/3) - u; | |
var d2 = d1 + 0.02/(k+1); | |
var z = (1 + g(s/u)) / u; | |
z = d2 * Math.sqrt(z); | |
z = NormalP( z ); | |
return z; | |
} | |
function PoissonTerm( u, k ) { | |
// by logs | |
return Math.exp( (k * Math.log(u)) - u - LnFact(k) ); | |
} | |
function PoissonP( u, k ) { | |
// term-by-term summation | |
if (k >= 20) return PoissonPD( u, k ); | |
else { | |
var sum = 0.0, j = 0; | |
while (j <= k) | |
sum += PoissonTerm( u, j++ ); | |
if (sum > 1) sum = 1; | |
return sum; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment