Python DevCenter
oreilly.comSafari Books Online.Conferences.


SimPy: Simulating Systems in Python
Pages: 1, 2

When finished with the staff member, the customer then releases and hangs up in the two yield release statements in lines 35 and 36. The released staff member can then pick up the customer waiting at the head of the queue. Similarly, the released phone line is immediately available for another customer.

The next few lines are housekeeping. We calculate the delay experienced (line 38), determine whether the customer is "happy" or not, incrementing the count of "happy" customers and and print out a trace line. (In practice this trace would be used only in debugging or to feed a statistical program for further analysis.) Then the customer leaves the system and the corresponding object vanishes.

Where do customers come from? They must arrive at random. Experienced simulators use a trick to simulate random events. The time between random arrivals is uncertain with an exponential probability distribution. All we need to do is to generate a sample from that distribution and to allow the Process to hold for that time. Each time we go round the loop a different number is generated and a different delay occurs. A statistician testing the resulting sequence of arrival times would be unable to detect any difference from pure randomness. We use that trick here.

An object of class Traffic generates a customer sequence (line 43). This is another SimPy Process and the active generator method is called generate (on line 51).

 43 class Traffic(Process):                          
 44     """Generates Customer arrivals"""
 45     Rate = 40.0   # (per hour) arrival rate      
 46     rv = Random() # a random variable            
 48     def __init__(self):
 49         Process.__init__(self)
 51     def generate(self):                          
 52         while True: 
 53             cust=Customer()  # new customer call 
 54             activate(cust,cust.serviceNeed())    
 55             timeToNext = Traffic.rv.expovariate(Traffic.Rate) 
 56             yield hold,self,timeToNext           

The Rate of arrivals is fixed on line 45. In a practical example this would be obtained from real data or from estimates and would most likely be read in. It may be a function of time of day as well. Line 46 establishes rv, a random generator.

We create a sequence of customers in an infinite loop. A customer is created in line 53 and the serviceNeed method activated in line 54. That customer acts independently from this point on. The time to the next arrival is generated by a sample from the correct distribution (line 55) and the yield hold simulates the delay. The required random number routines were imported from the standard Python module in line 5.

Finally we get to the main script that runs the simulation. Line 58 initializes the simulation system. Among other tasks this sets up the event scheduling system which will run the simulation clock and make sure events occur in the correct sequence. The next two lines establish the two Resources, the three phone lines, and the two staff. We assume that calls have no priority scheme and that queues have a normal first-come, first-served discipline.

Line 61 establishes the traffic object which will generate our randomly arriving customers. The next line activates it.

No simulation starts before line 63. The simulation will now run until time 6*24, that is, 24 hours a day for 6 days, at which point it will stop, and the next statement, printing out the results, is executed.

 58 initialize()                               
 59 phone   = Resource(capacity=3)               
 60 staff   = Resource(capacity=3)               
 61 traffic = Traffic()                          
 62 activate(traffic, traffic.generate())      
 63 simulate(until=6*24)     # hours           
 64 print "Total arrivals: %s / Total served: %s / Total unhappy: %s"\
 65       %(Customer.customers,Customer.customersServed,\
 66         Customer.customersServed - Customer.customersHappy)

So what do we do with this model? The original request was to discover the effect of changing the number of lines or the number of staff on customer happiness. To do this we must vary these numbers through a series of runs. We have to be careful about these experiments. Although using random numbers to generate the arrivals makes the model more realistic (randomness usually leads to queues), it means that a single run cannot be believed by itself. You have to make a series of replications to get a better idea of the result. Of course we can easily extend the displayed program to carry out series of runs, though such extensions are not shown here.

The SimPyCo helpdesk currently has a PABX with 3 incoming lines and 3 staff present. The helpdesk hours are Monday through Saturday, 24 hours a day. Plugging these figures into the simulation program shows a very high percentage of unhappy customers (99%) over the six day week.

To find out how many staff and lines are needed, we now run the simulation for 4 staff/4 lines and 5 staff/5 lines. The results are 86% and 0% unhappy customers, respectively. We repeat the run and now get 78% and 0%. So, as in the real world, the simulation shows variation from week to week, due to the randomness in the arrival of customer calls. The more often one runs the simulation, the better one can estimate the mean levels of unhappy customers.

This program uses the Open Source VPython plotting package ( Interfacing to VPython and other packages will be explained in a future article on SimPy. If you can't wait for that, download VPython and play with the program, it is simple enough. Enjoy!

There is another real world issue we can address with the simulation: does the level of unhappy customers change over the work week? To analyse the time behavior, we extended the program with graphical output.

We ran the program for the same 3/3, 4/4 and 5/5 options, for 5 simulated weeks. The graphs produced clearly show that in all 5 weeks,

  • the helpdesk with 3 lines/3 staff is rapidly saturated and stays saturated for the whole week,

    Figure 2 -- three lines and three staff members over five weeks

  • with 4 lines/4 staff, it shows great variability over time in delay times suffered by customers, with significant differences between weeks-- a highly unstable, unmanageable, unpredictable configuration; and

    Figure 3 -- four lines and four staff members over five weeks

  • with 5 lines/5 staff, only in one week out of the five simulated is there a period with any unhappy customer.

    Figure 4 -- five lines and five staff members over five weeks

The conclusion for SimPyCo management is that they must increase both the number of lines and the number of manned desks to at least 5 to cope with the current customer arrival rate of 40 calls per hour.

Looking Ahead

With its constructs Process, Resource, and Monitor (which we have not time to explain here), SimPy is a powerful but easy to use LEGO-like toolbox for describing and simulating many classes of complex dynamic systems, whether or not they yet exist. This power is greatly enhanced by the object orientation of Python, allowing easy extension by subclassing and inheriting. This way, generic models of frequently occurring situations ("the production line model", "the service counter model", "the network model", etc.) can be built and then used with little additional code for specific systems. Python gives further power to the SimPy user by being so richly endowed with interfaces to a wide variety of packages (many of which are open source), such as graphics, data bases, spreadsheets, and statistics.

We hope this article gave you a taste of the power and ease of use of SimPy. There are many facets of SimPy we have not touched on. how is SimPy using generators? How does one build OO models? How does one collect and analyze SimPy run data efficiently and elegantly? We will cover some of these in a future article. In the meantime, why not download SimPy, run its tutorial and test programs, and build your own simulation model? It is fun and might be profitable!

Related links

SimPy site: Download SimPy from here, including:

  • A brief cheat-sheet of the facilities that SimPy provides in the form of a listing of commands and methods for processes, resources, and monitors.
  • An extensive manual with simple examples.
  • An introduction to interfacing SimPy models with GUI and plotting applications.
  • The Bank, a tutorial for SimPy showing the gradual development of a multi-server bank model.
Fundamentals Of Object-Oriented Simulation

Klaus Müller is an Open Source software developer and a freelance consultant on military information systems.

Tony Vignaux does some teaching in simulation and continues his research interests.

Return to Python DevCenter.

Sponsored by: