Advertisement
Guest User

Simulador AD (Igor, Thais, Raffael)

a guest
Dec 12th, 2017
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 17.56 KB | None | 0 0
  1. import simpy
  2. import numpy
  3. import sys
  4. import argparse
  5. from decimal import *
  6. from random import Random, expovariate, uniform
  7. from datetime import datetime
  8. from confidence_interval import *
  9.  
  10. # Global variables (initialized by program's options).
  11. TOTAL_CLIENTS = None
  12. TOTAL_ROUNDS = None
  13. ARRIVAL_RATE = None
  14. SERVICE_RATE = 1.0
  15. LOG = None
  16. STATISTICS = None
  17. TRANSIENT = None
  18.  
  19. class Statistics(object):
  20.     """Class designed for generate simulation's statistics."""
  21.  
  22.     all_ex1 = []  # E[X_1] for each round.
  23.     all_ex2 = []  # E[x_2] for each round.
  24.     all_ew1 = []  # E[W_1] for each round.
  25.     all_ew2 = []  # E[W_2] for each round.
  26.     all_enq1 = [] # E[N_q1] for each round.
  27.     all_enq2 = [] # E[N_q2] for each round.
  28.     all_ens1 = [] # E[N_s1] for each round.
  29.     all_ens2 = [] # E[N_s2] for each round.
  30.  
  31.     w1s = [] # Time on waiting queue 1 for each cliente.
  32.     w2s = [] # Time on waiting queue 2 for each cliente.
  33.     x1s = [] # Time on server 1 for each cliente.
  34.     x2s = [] # Time on server 2 for each cliente.
  35.  
  36.     area_wq1 = 0 # Area from waiting queue 1.
  37.     area_wq2 = 0 # Area from waiting queue 2.
  38.     area_sq1 = 0 # Area from service 1.
  39.     area_sq2 = 0 # Area from waiting queue 2.
  40.  
  41.     total_time = 0 # Because env.now not work properly after the end.
  42.  
  43.     @staticmethod
  44.     def discart_first(n):
  45.         Statistics.w1s = Statistics.w1s[n:]
  46.         Statistics.w2s = Statistics.w2s[n:]
  47.         Statistics.x1s = Statistics.x1s[n:]
  48.         Statistics.x2s = Statistics.x2s[n:]
  49.  
  50.     @staticmethod
  51.     def show():
  52.         """Print statistics of one round of the simulation."""
  53.         print("Statistics:")
  54.  
  55.         ex1 = numpy.mean(numpy.array(Statistics.x1s))
  56.         ex2 = numpy.mean(numpy.array(Statistics.x2s))
  57.         ex = ex1 + ex2
  58.  
  59.         print("    E[X]   = E[X_1]  + E[X_2]  = %lf + %lf = %lf" % (ex1, ex2, ex))
  60.  
  61.         ew1 = numpy.mean(numpy.array(Statistics.w1s))
  62.         ew2 = numpy.mean(numpy.array(Statistics.w2s))
  63.         ew = ew1 + ew2
  64.  
  65.         print("    E[W]   = E[W_1]  + E[W_2]  = %lf + %lf = %lf" % (ew1, ew2, ew))
  66.         print("    E[T_1] = E[W_1]  + E[X_1]  = %lf + %lf = %lf" % (ew1, ex1, ew1 + ex1))
  67.         print("    E[T_2] = E[W_2]  + E[X_2]  = %lf + %lf = %lf" % (ew2, ex2, ew2 + ex2))
  68.         print("    E[T]   = E[T_1]  + E[T_2]  = %lf + %lf = %lf" % (ew1 + ex1, ew2 + ex2, ew1 + ex1 + ew2 + ex2))
  69.  
  70.         enq1 = Statistics.area_wq1 / Statistics.total_time
  71.         enq2 = Statistics.area_wq2 / Statistics.total_time
  72.         esq1 = Statistics.area_sq1 / Statistics.total_time
  73.         esq2 = Statistics.area_sq2 / Statistics.total_time
  74.  
  75.         print("    E[N_1] = E[N_q1] + E[N_s1] = %lf + %lf = %lf" % (enq1, esq1, enq1 + esq1))
  76.         print("    E[N_2] = E[N_q2] + E[N_s2] = %lf + %lf = %lf" % (enq2, esq2, enq2 + esq2))
  77.  
  78.         print("    Var(W_1) = %lf" % (numpy.var(numpy.array(Statistics.w1s))))
  79.         print("    Var(W_2) = %lf" % (numpy.var(numpy.array(Statistics.w2s))))
  80.         print("    Var(X_1) = %lf" % (numpy.var(numpy.array(Statistics.x1s))))
  81.         print("    Var(X_2) = %lf" % (numpy.var(numpy.array(Statistics.x2s))))
  82.  
  83.     @staticmethod
  84.     def reset():
  85.         """Reset all parameters. Useful between rounds."""
  86.  
  87.         Statistics.all_ex1.append(numpy.mean(numpy.array(Statistics.x1s)))
  88.         Statistics.all_ex2.append(numpy.mean(numpy.array(Statistics.x2s)))
  89.  
  90.         Statistics.all_ew1.append(numpy.mean(numpy.array(Statistics.w1s)))
  91.         Statistics.all_ew2.append(numpy.mean(numpy.array(Statistics.w2s)))
  92.  
  93.         Statistics.all_enq1.append(Statistics.area_wq1 / Statistics.total_time)
  94.         Statistics.all_enq2.append(Statistics.area_wq2 / Statistics.total_time)
  95.         Statistics.all_ens1.append(Statistics.area_sq1 / Statistics.total_time)
  96.         Statistics.all_ens2.append(Statistics.area_sq2 / Statistics.total_time)
  97.  
  98.         Statistics.w1s = []
  99.         Statistics.w2s = []
  100.         Statistics.x1s = []
  101.         Statistics.x2s = []
  102.  
  103.         Statistics.area_wq1 = 0
  104.         Statistics.area_wq2 = 0
  105.         Statistics.area_sq1 = 0
  106.         Statistics.area_sq2 = 0
  107.  
  108.         Statistics.total_time = 0
  109.  
  110.     @staticmethod
  111.     def clear():
  112.         """Reset all parameters. Useful between rounds."""
  113.  
  114.         Statistics.all_ex1 = []
  115.         Statistics.all_ex2 = []
  116.  
  117.         Statistics.all_ew1 = []
  118.         Statistics.all_ew2 = []
  119.  
  120.         Statistics.all_enq1 = []
  121.         Statistics.all_enq2 = []
  122.         Statistics.all_ens1 = []
  123.         Statistics.all_ens2 = []
  124.  
  125.         Statistics.w1s = []
  126.         Statistics.w2s = []
  127.         Statistics.x1s = []
  128.         Statistics.x2s = []
  129.  
  130.         Statistics.area_wq1 = 0
  131.         Statistics.area_wq2 = 0
  132.         Statistics.area_sq1 = 0
  133.         Statistics.area_sq2 = 0
  134.  
  135.         Statistics.total_time = 0
  136.  
  137. class Log(object):
  138.     """Log control"""
  139.  
  140.     @staticmethod
  141.     def msg1(now, lenght1, length2):
  142.         if LOG: print("%lf: Queues' length are: (%d, %d)." % (now, lenght1, length2))
  143.  
  144.     @staticmethod
  145.     def msg2(now, id, client_class, service_time):
  146.         if LOG: print("%lf: Client %d (of class %d) got a being served now and needs %lf time units." % (now, id, client_class, service_time))
  147.  
  148.     @staticmethod
  149.     def msg3(now, id, client_class):
  150.         if LOG: print("%lf: Finished attending client %d, of class %d." % (now, id, client_class))
  151.  
  152.     @staticmethod
  153.     def msg4(now, id, service_time):
  154.         if LOG: print("%lf: Server interrupted! Client %d (of class 2) will finish in %lf time units." % (now, id, service_time))
  155.  
  156.     @staticmethod
  157.     def msg5(now, id):
  158.         if LOG: print("%lf: Server woke up and will serve client %d" % (now, id))
  159.  
  160.     @staticmethod
  161.     def msg6(now, id, client_class, service_time, current_class_on_server):
  162.         if LOG: print("%lf: Client %d (of class %d) arrives and will need %lf for service. Current class on server: %d." % (now, id, client_class, service_time, current_class_on_server))
  163.  
  164.     @staticmethod
  165.     def msg7(now, id):
  166.         if LOG: print("%lf: Interrupting server because client %d more important." % (now, id))
  167.  
  168. class Server(object):
  169.     """Class that represents a server."""
  170.     def __init__(self, env):
  171.         """Constructor of a server object."""
  172.         self.env = env
  173.         self.action = env.process(self.run()) # Start the run process everytime an instance is created.
  174.         self.service_2_starting_time = 0 # It'll be useful when client of class 2 is interrupted.
  175.  
  176.         self.queue_1 = [] # Waiting queue 1.
  177.         self.queue_2 = [] # Waiting queue 2.
  178.  
  179.         self.ndone = 0 # Number of clients fully served.
  180.         self.current_class_on_server = 0 # 1 if client of class 1 is being served, 2 if client of class 2 is being served, 0 otherwise.
  181.  
  182.         # Statistics.
  183.         self.last_wq1_event_time = 0 # Last time when someone arrived or left waiting queue 1.
  184.         self.last_wq2_event_time = 0 # Last time when someone arrived or left waiting queue 2.
  185.         self.last_sq1_event_time = 0 # Last time when someone arrived or left service 1.
  186.         self.last_sq2_event_time = 0 # Last time when someone arrived or left service 2.
  187.  
  188.     def run(self):
  189.         """Server activities (behaviour) on simulation."""
  190.  
  191.         while self.ndone < TOTAL_CLIENTS:
  192.             try:
  193.                 # If server is idle, it waits until next client arrives.
  194.                 while (len(self.queue_1) == 0 and len(self.queue_2) == 0):
  195.                     forever = 999999999999999999999999999999999999999
  196.                     yield self.env.timeout(forever)
  197.  
  198.                 Log().msg1(self.env.now, len(self.queue_1), len(self.queue_2))
  199.  
  200.                 # Serve job at head of queue 1.
  201.                 if (len(self.queue_1) > 0):
  202.                     Log().msg2(self.env.now, self.queue_1[0].id, 1, self.queue_1[0].service_time)
  203.  
  204.                     self.current_class_on_server = 1 # Client of class 1 is being served.
  205.  
  206.                     Statistics.w1s.append(self.env.now - self.queue_1[0].arrival_time) # Save waiting time for this client for later.
  207.  
  208.                     Statistics.area_wq1 += (self.env.now - self.last_wq1_event_time) * len(self.queue_1) # First client of queue 1 is lefting waiting queue. Update wq1 area to find E[N_q1].
  209.                     self.last_wq1_event_time = self.env.now
  210.  
  211.                     self.last_sq1_event_time = self.env.now
  212.                     yield self.env.timeout(self.queue_1[0].service_time) # Serve client 1.
  213.                     Statistics.area_sq1 += (self.env.now - self.last_sq1_event_time) * 1 # First client of queue 1 left server 1. Update sq1 area to find E[N_s1].
  214.  
  215.                     # After first service, the client will have another service time, for the second service.
  216.                     self.queue_1[0].service_time = Random().expovariate(SERVICE_RATE)
  217.                     Statistics.x2s.append(self.queue_1[0].service_time)
  218.  
  219.                     Statistics.area_wq2 += (self.env.now - self.last_wq2_event_time) * len(self.queue_2) # First client of queue 1 is joining waiting queue 2. Update wq2 area to find E[N_q2].
  220.                     self.last_wq2_event_time = self.env.now
  221.  
  222.                     self.queue_2.append(self.queue_1[0])
  223.                     self.queue_2[-1].arrival_time = self.env.now
  224.  
  225.                     Log().msg3(self.env.now, self.queue_1[0].id, 1)
  226.                     del self.queue_1[0] # Remove client from queue 1 (because it's now on queue 2).
  227.  
  228.                 # Serve job at head of queue 2.
  229.                 else:
  230.                     Log().msg2(self.env.now, self.queue_2[0].id, 2, self.queue_2[0].service_time)
  231.                     self.current_class_on_server = 2 # Client of class 2 is being served.
  232.                     service_2_starting_time = self.env.now # It'll be useful when client of class 2 is interrupted.
  233.  
  234.                     Statistics.area_wq2 += (self.env.now - self.last_wq2_event_time) * len(self.queue_2) # First client of queue 2 is lefting waiting queue. Update wq2 area to find E[N_q2].
  235.                     self.last_wq2_event_time = self.env.now
  236.  
  237.                     self.queue_2[0].waiting_time_in_queue_2 += (self.env.now - self.queue_2[0].arrival_time) # Each client knows how much time spent on waiting queue 2.
  238.  
  239.                     self.last_sq2_event_time = self.env.now
  240.                     yield self.env.timeout(self.queue_2[0].service_time) # Serve client 2.
  241.                     Statistics.area_sq2 += (self.env.now - self.last_sq2_event_time) * 1 # First client of queue 2 left server 2. Update sq2 area to find E[N_s2].
  242.  
  243.                     Log().msg3(self.env.now, self.queue_2[0].id, 2)
  244.  
  245.                     self.ndone += 1
  246.                     Statistics.w2s.append(self.queue_2[0].waiting_time_in_queue_2) # Waiting queue 2 is saved now because interruptions could happen at any time.
  247.                     del self.queue_2[0]
  248.  
  249.                     self.current_class_on_server = 0
  250.  
  251.             except simpy.Interrupt:
  252.                 # If client of class 1 arrives while a client of class 2 is being served.
  253.                 if (self.current_class_on_server == 2):
  254.                     self.queue_2[0].service_time -= self.env.now - service_2_starting_time # Update service time needed by client partially.
  255.                     Log().msg4(self.env.now, self.queue_2[0].id, self.queue_2[0].service_time)
  256.  
  257.                     Statistics.area_sq2 += (self.env.now - self.last_sq2_event_time) * 1 # Client of server 2 left. Update sq2 area to find E[N_s2].
  258.  
  259.                     Statistics.area_wq2 += (self.env.now - self.last_wq2_event_time) * (len(self.queue_2) - 1) # It's like current client (of class 2) arrives on queue 2 again. Update wq2 area to find E[N_q2].
  260.                     self.last_wq2_event_time = self.env.now
  261.                     self.queue_2[0].arrival_time = self.env.now
  262.  
  263.                 # If client of class 1 arrives when server is idle.
  264.                 elif (self.current_class_on_server == 0):
  265.                     Log().msg5(self.env.now, self.queue_1[0].id)
  266.  
  267.         Statistics.total_time = self.env.now # Because env.now goes crazy at the end of the simulation.
  268.  
  269. class Client(object):
  270.     """Class that reoresents a client (or an arrival)."""
  271.  
  272.     LAST_ARRIVAL_TIME = 0 # Needed because the time between arives is exponential. (Don't forget to reset between rounds!)
  273.  
  274.     def __init__(self, env, server, i):
  275.         """Constructor of a client object."""
  276.  
  277.         self.env = env
  278.         self.server = server
  279.         self.id = i
  280.         self.client_class = 1
  281.         self.action = env.process(self.run()) # Start the run process everytime an instance is created.
  282.  
  283.         self.arrival_time = Client.LAST_ARRIVAL_TIME + Random().expovariate(ARRIVAL_RATE) # Time when client will arrive on queue.
  284.         self.service_time = Random().expovariate(SERVICE_RATE) # Time client will waste being served.
  285.  
  286.         Statistics.x1s.append(self.service_time) # Save service time for later.
  287.         Client.LAST_ARRIVAL_TIME = self.arrival_time
  288.  
  289.         self.waiting_time_in_queue_2 = 0
  290.  
  291.     def run(self):
  292.         """Client activities (behaviour) on simulation."""
  293.  
  294.         # Client is living somewhere else and will be woken up when arrives on waiting queue.
  295.         yield self.env.timeout(self.arrival_time)
  296.  
  297.         # Client arrives on waiting queue to be served eventually.
  298.         waiting_queue1_length = len(self.server.queue_1)
  299.         if self.server.current_class_on_server == 1: waiting_queue1_length -= 1 # If there's some client of class 1 being served, only len(queue_1) - 1 is in waiting queue.
  300.  
  301.         Statistics.area_wq1 += (self.env.now - self.server.last_wq1_event_time) * waiting_queue1_length # Client is joining waiting queue 1. Update wq1 area to find E[N_q1].
  302.         self.server.last_wq1_event_time = self.env.now
  303.  
  304.         self.server.queue_1.append(self)
  305.  
  306.         Log().msg6(self.env.now, self.id, self.client_class, self.service_time, self.server.current_class_on_server)
  307.  
  308.         # If server is sleeping because it's idle.
  309.         if (len(self.server.queue_2) == 0 and len(self.server.queue_1) == 1):
  310.             self.server.action.interrupt()
  311.  
  312.         # If there is a client of class 2 on server, this client will interrompt it to be served (class 1 has priority over class 2)
  313.         elif (self.server.current_class_on_server == 2):
  314.             Log().msg7(self.env.now, self.id)
  315.             self.server.action.interrupt()
  316.  
  317. def main():
  318.     """Main function. It creates one server and TOTAL_CLIENTS clients. Then, it runs the environment for simulation."""
  319.     print('Starting simulation with %d clients and %d rounds, with arrival rate equals %lf' % (TOTAL_CLIENTS, TOTAL_ROUNDS, ARRIVAL_RATE))
  320.  
  321.     for _ in range(TOTAL_ROUNDS):
  322.         env = simpy.Environment()
  323.         server = Server(env)
  324.         clients = [Client(env, server, i) for i in range(TOTAL_CLIENTS)]
  325.         env.run()
  326.  
  327.         if LOG and STATISTICS: print("")
  328.         if STATISTICS: Statistics.show()
  329.         #Statistics.discart_first(TRANSIENT)
  330.         Statistics.reset() # Reset statistics between rounds.
  331.         Client.LAST_ARRIVAL_TIME = 0 # Reset static data in client.
  332.  
  333.     print("E[X_1]")
  334.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ex1]))
  335.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ex1))))
  336.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ex1))))
  337.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ex1))))
  338.  
  339.     print("E[X_2]")
  340.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ex2]))
  341.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ex2))))
  342.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ex2))))
  343.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ex2))))
  344.  
  345.     print("E[W_1]")
  346.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ew1]))
  347.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ew1))))
  348.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ew1))))
  349.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ew1))))
  350.  
  351.     print("E[W_2]")
  352.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ew2]))
  353.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ew2))))
  354.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ew2))))
  355.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ew2))))
  356.  
  357.     print("E[N_q1]")
  358.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_enq1]))
  359.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_enq1))))
  360.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_enq1))))
  361.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_enq1))))
  362.  
  363.     print("E[N_q2]")
  364.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_enq2]))
  365.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_enq2))))
  366.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_enq2))))
  367.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_enq2))))
  368.  
  369.     print("E[N_s1]")
  370.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ens1]))
  371.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ens1))))
  372.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ens1))))
  373.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ens1))))
  374.  
  375.     print("E[N_s2]")
  376.     print("    " + str([float(Decimal("%.5lf" % x)) for x in Statistics().all_ens2]))
  377.     print("    MEAN: %.5lf" % (numpy.mean(numpy.array(Statistics().all_ens2))))
  378.     print("    VARIANCE: %.5lf" % (numpy.var(numpy.array(Statistics().all_ens2))))
  379.     print("    STD: %.5lf\n" % (numpy.std(numpy.array(Statistics().all_ens2))))
  380.  
  381.     t_student(Statistics(), TOTAL_ROUNDS)
  382.     chi_square(Statistics(), TOTAL_ROUNDS)
  383.  
  384. if __name__ == "__main__":
  385.     """Python stuff."""
  386.     parser = argparse.ArgumentParser(description="Project of the course Avaliacao & Desempenho (UFRJ). Made by Igor Carpanese, Thais Luca and Raffael Siqueira.", formatter_class=lambda prog: argparse.HelpFormatter(prog, max_help_position=120))
  387.     parser.add_argument('-c', '--clients', type=int, default=10000, help='number of clients (default: 10000)')
  388.     parser.add_argument('-r', '--rounds', type=int, default=1, help='number of rounds (default: 1)')
  389.     parser.add_argument('-l', '--lambda', type=float, default=0.1, help='arrival rate (default: 0.1)')
  390.     parser.add_argument('-t', '--transient', type=int, default=0, help='ignore first clients (default: 0)')
  391.     parser.add_argument('--log', default=False, action='store_true', help='print simulation log (default: False)')
  392.     parser.add_argument('--statistics', default=False, action='store_true', help='print data for each round (default: False)')
  393.     parser.add_argument('-v', '--version', action='version', version='SIM 1.0')
  394.     args = vars(parser.parse_args())
  395.  
  396.     TOTAL_CLIENTS = args["clients"]
  397.     TOTAL_ROUNDS = args["rounds"]
  398.     ARRIVAL_RATE = args["lambda"]
  399.     LOG = args["log"]
  400.     STATISTICS = args["statistics"]
  401.     TRANSIENT = args["transient"]
  402.  
  403.     if TRANSIENT >= TOTAL_CLIENTS:
  404.         print("Number of clients in transient phrase cannot be greater than total number of clients")
  405.     elif TOTAL_ROUNDS < 30:
  406.         print("Simulation does not work with proper precision for less than 30 rounds.")
  407.     else:
  408.         main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement