Skip to content

Instantly share code, notes, and snippets.

@pengelbrecht
Created July 10, 2018 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pengelbrecht/be4571dd4fd215866c5e4cf805138fef to your computer and use it in GitHub Desktop.
Save pengelbrecht/be4571dd4fd215866c5e4cf805138fef to your computer and use it in GitHub Desktop.
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 agentOccupancy(callDuration, calls, periodLength, agents) {
return(callDuration * calls / (periodLength * agents))
}
function averageSpeedOfAnswer(callDuration, calls, periodLength, agents) {
var U = callDuration * calls / periodLength;
var o = U / agents;
var ec = PoissonTerm(U, agents)/(PoissonTerm(U, agents) + (1-o)*PoissonP(U,agents-1));
return(ec * callDuration /(agents * (1 - o)));
}
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