Multiteller Bank With Jockeying

Simlib to simulate a multiteller bank where the customers are allowed to jockey (move) from one queue to another if it seems to be to their advantage. A bank with five tellers opens its doors at 9 A.M. and closes its doors at 5 P.M., but operates until all customers in the bank by 5 P.M. have been served. Assume that the interarrival times of customers are IID exponential random variables with mean 1 minutes and that service times of customers are IID exponential random variables with mean 4.5 minutes…………….

mtbank.c

/* External definitions for multiteller bank. */

#include “simlib.h” /* Required for use of simlib.c. */

#define EVENT_ARRIVAL 1 /* Event type for arrival of a customer. */
#define EVENT_DEPARTURE 2 /* Event type for departure of a customer. */
#define EVENT_CLOSE_DOORS 3 /* Event type for closing doors at 5 P.M. */
#define SAMPST_DELAYS 1 /* sampst variable for delays in queue(s). */
#define STREAM_INTERARRIVAL 1 /* Random-number stream for interarrivals. */
#define STREAM_SERVICE 2 /* Random-number stream for service times. */

/* Declare non-simlib global variables. */

int min_tellers, max_tellers, num_tellers, shortest_length, shortest_queue;
float mean_interarrival, mean_service, length_doors_open;
FILE *infile, *outfile;

/* Declare non-simlib functions. */

void arrive(void);
void depart(int teller);
void jockey(int teller);
void report(void);

int main() /* Main function. */
{
/* Open input and output files. */

infile = fopen(“mtbank.in”, “r”);
outfile = fopen(“mtbank.out”, “w”);

/* Read input parameters. */

fscanf(infile, “%d %d %f %f %f”, &min_tellers, &max_tellers,
&mean_interarrival, &mean_service, &length_doors_open);

/* Write report heading and input parameters. */

fprintf(outfile, “Multiteller bank with separate queues & jockeying\n\n”);
fprintf(outfile, “Number of tellers%16d to%3d\n\n”,
min_tellers, max_tellers);
fprintf(outfile, “Mean interarrival time%11.3f minutes\n\n”,
mean_interarrival);
fprintf(outfile, “Mean service time%16.3f minutes\n\n”, mean_service);
fprintf(outfile,
“Bank closes after%16.3f hours\n\n\n\n”, length_doors_open);

/* Run the simulation varying the number of tellers. */

for (num_tellers = min_tellers; num_tellers <= max_tellers; ++num_tellers) {

/* Initialize simlib */

init_simlib();

/* Set maxatr = max(maximum number of attributes per record, 4) */

maxatr = 4; /* NEVER SET maxatr TO BE SMALLER THAN 4. */

/* Schedule the first arrival. */

event_schedule(expon(mean_interarrival, STREAM_INTERARRIVAL),
EVENT_ARRIVAL);

/* Schedule the bank closing. (Note need for consistency of units.) */

event_schedule(60 * length_doors_open, EVENT_CLOSE_DOORS);

/* Run the simulation while the event list is not empty. */

while (list_size[LIST_EVENT] != 0) {

/* Determine the next event. */

timing();

/* Invoke the appropriate event function. */

switch (next_event_type) {

case EVENT_ARRIVAL:
arrive();
break;
case EVENT_DEPARTURE:
depart((int) transfer[3]); /* transfer[3] is teller
number. */
break;
case EVENT_CLOSE_DOORS:
event_cancel(EVENT_ARRIVAL);
break;
}
}

/* Report results for the simulation with num_tellers tellers. */

report();
}

fclose(infile);
fclose(outfile);

return 0;
}

void arrive(void) /* Event function for arrival of a customer to the bank. */
{
int teller;

/* Schedule next arrival. */

event_schedule(sim_time + expon(mean_interarrival, STREAM_INTERARRIVAL),
EVENT_ARRIVAL);

/* If a teller is idle, start service on the arriving customer. */

for (teller = 1; teller <= num_tellers; ++teller) {

if (list_size[num_tellers + teller] == 0) {

/* This teller is idle, so customer has delay of zero. */

sampst(0.0, SAMPST_DELAYS);

/* Make this teller busy (attributes are irrelevant). */

list_file(FIRST, num_tellers + teller);

/* Schedule a service completion. */

transfer[3] = teller; /* Define third attribute of type-two event-
list record before event_schedule. */

event_schedule(sim_time + expon(mean_service, STREAM_SERVICE),
EVENT_DEPARTURE);

/* Return control to the main function. */

return;
}
}

/* All tellers are busy, so find the shortest queue (leftmost shortest in
case of ties). */

shortest_length = list_size[1];
shortest_queue = 1;
for (teller = 2; teller <= num_tellers; ++teller)
if (list_size[teller] < shortest_length) {
shortest_length = list_size[teller];
shortest_queue = teller;
}

/* Place the customer at the end of the leftmost shortest queue. */

transfer[1] = sim_time;
list_file(LAST, shortest_queue);
}

void depart(int teller) /* Departure event function. */
{
/* Check to see whether the queue for teller “teller” is empty. */

if (list_size[teller] == 0)

/* The queue is empty, so make the teller idle. */

list_remove(FIRST, num_tellers + teller);

else {

/* The queue is not empty, so start service on a customer. */

list_remove(FIRST, teller);
sampst(sim_time – transfer[1], SAMPST_DELAYS);
transfer[3] = teller; /* Define before event_schedule. */
event_schedule(sim_time + expon(mean_service, STREAM_SERVICE),
EVENT_DEPARTURE);
}

/* Let a customer from the end of another queue jockey to the end of this
queue, if possible. */

jockey(teller);
}

void jockey(int teller) /* Jockey a customer to the end of queue “teller” from
the end of another queue, if possible. */
{
int jumper, min_distance, ni, nj, other_teller, distance;

/* Find the number, jumper, of the queue whose last customer will jockey to
queue or teller “teller”, if there is such a customer. */

jumper = 0;
min_distance = 1000;
ni = list_size[teller] + list_size[num_tellers + teller];

/* Scan all the queues from left to right. */

for (other_teller = 1; other_teller <= num_tellers; ++other_teller) {

nj = list_size[other_teller] + list_size[num_tellers + other_teller];
distance = abs(teller – other_teller);

/* Check whether the customer at the end of queue other_teller qualifies
for being the jockeying choice so far. */

if (other_teller != teller && nj > ni + 1 && distance < min_distance) {

/* The customer at the end of queue other_teller is our choice so
far for the jockeying customer, so remember his queue number and
its distance from the destination queue. */

jumper = other_teller;
min_distance = distance;
}
}

/* Check to see whether a jockeying customer was found. */

if (jumper > 0) {

/* A jockeying customer was found, so remove him from his queue. */

list_remove(LAST, jumper);

/* Check to see whether the teller of his new queue is busy. */

if (list_size[num_tellers + teller] > 0)

/* The teller of his new queue is busy, so place the customer at the
end of this queue. */

list_file(LAST, teller);

else {

/* The teller of his new queue is idle, so tally the jockeying
customer’s delay, make the teller busy, and start service. */

sampst(sim_time – transfer[1], SAMPST_DELAYS);
list_file(FIRST, num_tellers + teller);
transfer[3] = teller; /* Define before event_schedule. */
event_schedule(sim_time + expon(mean_service, STREAM_SERVICE),
EVENT_DEPARTURE);
}
}
}

void report(void) /* Report generator function. */
{
int teller;
float avg_num_in_queue;

/* Compute and write out estimates of desired measures of performance. */

avg_num_in_queue = 0.0;
for (teller = 1; teller <= num_tellers; ++teller)
avg_num_in_queue += filest(teller);
fprintf(outfile, “\n\nWith%2d tellers, average number in queue = %10.3f”,
num_tellers, avg_num_in_queue);
fprintf(outfile, “\n\nDelays in queue, in minutes:\n”);
out_sampst(outfile, SAMPST_DELAYS, SAMPST_DELAYS);
}

simlib.c, simlib.h, simlibdefs.h can be found here

mtbank.in – Simulation Input

Input Parameters : minimal number of tellers, maximal number of tellers, mean interarrival time, mean service time and length doors open (hours).

mtbank.out – Simulation Result

Reference :
Textbook : Simulation Modeling and Analysis

Strive to be independence

April 15, 2008
Taipei City
High Speed Network Lab

Udin Harun

Comments are closed.

%d bloggers like this: