


from collections import deque

class     UpperCAmelCase__ :



     '''simple docstring'''




     def __init__(			self							:							List[str]						,   UpperCamelCase							:							int						,   UpperCamelCase							:							Tuple						,   UpperCamelCase							:							Dict		):





            """simple docstring"""



            _lowercase       :					Dict     							=      process_name  # process name
            _lowercase       :					List[str]     							=      arrival_time  # arrival time of the process
            # completion time of finished process or last interrupted time
            _lowercase       :					Dict     							=      arrival_time
            _lowercase       :					str     							=      burst_time  # remaining burst time
            _lowercase       :					Optional[Any]     							=      0  # total time of the process wait in ready queue
            _lowercase       :					str     							=      0  # time from arrival time to completion time




class     UpperCAmelCase__ :



     '''simple docstring'''




     def __init__(			self							:							Optional[int]						,   UpperCamelCase							:							Optional[int]						,   UpperCamelCase							:							Tuple						,   UpperCamelCase							:							str						,   UpperCamelCase							:							int						,   ):





            """simple docstring"""



            _lowercase       :					Optional[int]     							=      number_of_queues
            # time slice of queues that round robin algorithm applied
            _lowercase       :					List[Any]     							=      time_slices
            # unfinished process is in this ready_queue
            _lowercase       :					Dict     							=      queue
            # current time
            _lowercase       :					List[Any]     							=      current_time
            # finished process is in this sequence queue
            _lowercase       :					Dict     							=      deque()




     def 	lowerCAmelCase_ (			self							:							Optional[int]		):





            """simple docstring"""



            _lowercase       :					Optional[Any]     							=      []
            for i in range(len(self.finish_queue		)		):
                   sequence.append(self.finish_queue[i].process_name		)
            return sequence




     def 	lowerCAmelCase_ (			self							:							Dict						,   UpperCamelCase							:							Dict		):





            """simple docstring"""



            _lowercase       :					Any     							=      []
            for i in range(len(__snake_case		)		):
                   waiting_times.append(queue[i].waiting_time		)
            return waiting_times




     def 	lowerCAmelCase_ (			self							:							int						,   UpperCamelCase							:							List[Any]		):





            """simple docstring"""



            _lowercase       :					List[Any]     							=      []
            for i in range(len(__snake_case		)		):
                   turnaround_times.append(queue[i].turnaround_time		)
            return turnaround_times




     def 	lowerCAmelCase_ (			self							:							List[Any]						,   UpperCamelCase							:							Dict		):





            """simple docstring"""



            _lowercase       :					Any     							=      []
            for i in range(len(__snake_case		)		):
                   completion_times.append(queue[i].stop_time		)
            return completion_times




     def 	lowerCAmelCase_ (			self							:							List[Any]						,   UpperCamelCase							:							List[Any]		):





            """simple docstring"""



            return [q.burst_time for q in queue]




     def 	lowerCAmelCase_ (			self							:							Dict						,   UpperCamelCase							:							str		):





            """simple docstring"""



            process.waiting_time += self.current_time - process.stop_time
            return process.waiting_time




     def 	lowerCAmelCase_ (			self							:							List[Any]						,   UpperCamelCase							:							str		):





            """simple docstring"""



            _lowercase       :					Optional[Any]     							=      deque()  # sequence deque of finished process
            while len(__snake_case		) != 0:
                   _lowercase       :					Optional[int]     							=      ready_queue.popleft()  # current process

                   # if process's arrival time is later than current time, update current time
                   if self.current_time < cp.arrival_time:
                          self.current_time += cp.arrival_time

                   # update waiting time of current process
                   self.update_waiting_time(__snake_case		)
                   # update current time
                   self.current_time += cp.burst_time
                   # finish the process and set the process's burst-time 0
                   _lowercase       :					List[Any]     							=      0
                   # set the process's turnaround time because it is finished
                   _lowercase       :					Any     							=      self.current_time - cp.arrival_time
                   # set the completion time
                   _lowercase       :					str     							=      self.current_time
                   # add the process to queue that has finished queue
                   finished.append(__snake_case		)

            self.finish_queue.extend(__snake_case		)  # add finished process to finish queue
            # FCFS will finish all remaining processes
            return finished




     def 	lowerCAmelCase_ (			self							:							Any						,   UpperCamelCase							:							Optional[Any]						,   UpperCamelCase							:							Dict		):





            """simple docstring"""



            _lowercase       :					Union[str, Any]     							=      deque()  # sequence deque of terminated process
            # just for 1 cycle and unfinished processes will go back to queue
            for _ in range(len(__snake_case		)		):
                   _lowercase       :					List[Any]     							=      ready_queue.popleft()  # current process

                   # if process's arrival time is later than current time, update current time
                   if self.current_time < cp.arrival_time:
                          self.current_time += cp.arrival_time

                   # update waiting time of unfinished processes
                   self.update_waiting_time(__snake_case		)
                   # if the burst time of process is bigger than time-slice
                   if cp.burst_time > time_slice:
                          # use CPU for only time-slice
                          self.current_time += time_slice
                          # update remaining burst time
                          cp.burst_time -= time_slice
                          # update end point time
                          _lowercase       :					List[Any]     							=      self.current_time
                          # locate the process behind the queue because it is not finished
                          ready_queue.append(__snake_case		)
                   else:
                          # use CPU for remaining burst time
                          self.current_time += cp.burst_time
                          # set burst time 0 because the process is finished
                          _lowercase       :					Optional[int]     							=      0
                          # set the finish time
                          _lowercase       :					Union[str, Any]     							=      self.current_time
                          # update the process' turnaround time because it is finished
                          _lowercase       :					str     							=      self.current_time - cp.arrival_time
                          # add the process to queue that has finished queue
                          finished.append(__snake_case		)

            self.finish_queue.extend(__snake_case		)  # add finished process to finish queue
            # return finished processes queue and remaining processes queue
            return finished, ready_queue




     def 	lowerCAmelCase_ (			self							:							List[Any]		):





            """simple docstring"""



            for i in range(self.number_of_queues - 1		):
                   _lowercase							,						_lowercase       :					int     							=      self.round_robin(
                       self.ready_queue						,   self.time_slices[i]		)
            #  the last queue has first_come_first_served algorithm
            self.first_come_first_served(self.ready_queue		)

            return self.finish_queue


if __name__ == "__main__":
   import doctest

   UpperCamelCase__												=      Process('P1', 0, 53)
   UpperCamelCase__												=      Process('P2', 0, 17)
   UpperCamelCase__												=      Process('P3', 0, 68)
   UpperCamelCase__												=      Process('P4', 0, 24)
   UpperCamelCase__												=      3
   UpperCamelCase__												=      [17, 25]
   UpperCamelCase__												=      deque([Pa, Pa, Pa, Pa])

   if len(time_slices) != number_of_queues - 1:
      raise SystemExit(0)

   doctest.testmod(extraglobs={'queue': deque([Pa, Pa, Pa, Pa])})

   UpperCamelCase__												=      Process('P1', 0, 53)
   UpperCamelCase__												=      Process('P2', 0, 17)
   UpperCamelCase__												=      Process('P3', 0, 68)
   UpperCamelCase__												=      Process('P4', 0, 24)
   UpperCamelCase__												=      3
   UpperCamelCase__												=      [17, 25]
   UpperCamelCase__												=      deque([Pa, Pa, Pa, Pa])
   UpperCamelCase__												=      MLFQ(number_of_queues, time_slices, queue, 0)
   UpperCamelCase__												=      mlfq.multi_level_feedback_queue()

   # print total waiting times of processes(P1, P2, P3, P4)
   print(
       F"""waiting time:\
        \t\t\t{MLFQ.calculate_waiting_time(mlfq, [Pa, Pa, Pa, Pa])}"""
   )
   # print completion times of processes(P1, P2, P3, P4)
   print(
       F"""completion time:\
        \t\t{MLFQ.calculate_completion_time(mlfq, [Pa, Pa, Pa, Pa])}"""
   )
   # print total turnaround times of processes(P1, P2, P3, P4)
   print(
       F"""turnaround time:\
        \t\t{MLFQ.calculate_turnaround_time(mlfq, [Pa, Pa, Pa, Pa])}"""
   )
   # print sequence of finished processes
   print(
       F"""sequence of finished processes:\
        {mlfq.calculate_sequence_of_finish_queue()}"""
   )






def      UpperCAmelCase_    (    _UpperCAmelCase							:Any  ,						_UpperCAmelCase							:Dict				)	->				Union[str, Any]:
     '''simple docstring'''


     A_          =       [1]
     for i in range(2  ,						_UpperCAmelCase				):
          factorials.append(factorials[-1] * i				)
     assert 0 <= k < factorials[-1] * n, "k out of bounds"

     A_          =       []
     A_          =       list(range(_UpperCAmelCase				)				)

     # Find permutation
     while factorials:
          A_          =       factorials.pop()
          A_   ,    A_          =       divmod(_UpperCAmelCase  ,						_UpperCAmelCase				)
          permutation.append(elements[number]				)
          elements.remove(elements[number]				)
     permutation.append(elements[0]				)

     return permutation


if __name__ == "__main__":
      import doctest

      doctest.testmod()



