



"""simple docstring"""
from collections import deque



class    SCREAMING_SNAKE_CASE__						:

   def __init__(     self   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE		)						->   None:





    '''simple docstring'''




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



class    SCREAMING_SNAKE_CASE__						:

   def __init__(     self   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE   ,  )						->   None:





    '''simple docstring'''




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

   def 			SCREAMING_SNAKE_CASE  (     self		)						->   list[str]:





    '''simple docstring'''




    UpperCAmelCase			:      Tuple			=			[]
    for i in range(len(self.finish_queue		)		):
     sequence.append(self.finish_queue[i].process_name		)
    return sequence

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   list[int]:





    '''simple docstring'''




    UpperCAmelCase			:      Optional[int]			=			[]
    for i in range(len(UpperCamelCase_		)		):
     waiting_times.append(queue[i].waiting_time		)
    return waiting_times

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   list[int]:





    '''simple docstring'''




    UpperCAmelCase			:      Optional[Any]			=			[]
    for i in range(len(UpperCamelCase_		)		):
     turnaround_times.append(queue[i].turnaround_time		)
    return turnaround_times

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   list[int]:





    '''simple docstring'''




    UpperCAmelCase			:      Optional[Any]			=			[]
    for i in range(len(UpperCamelCase_		)		):
     completion_times.append(queue[i].stop_time		)
    return completion_times

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   list[int]:





    '''simple docstring'''




    return [q.burst_time for q in queue]

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   int:





    '''simple docstring'''




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

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE		)						->   deque[Process]:





    '''simple docstring'''




    UpperCAmelCase			:      deque[Process]			=			deque()  # sequence deque of finished process
    while len(UpperCamelCase_		) != 0:
     UpperCAmelCase			:      Dict			=			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(UpperCamelCase_		)
     # update current time
     self.current_time += cp.burst_time
     # finish the process and set the process's burst-time 0
     UpperCAmelCase			:      Any			=			0
     # set the process's turnaround time because it is finished
     UpperCAmelCase			:      Optional[Any]			=			self.current_time - cp.arrival_time
     # set the completion time
     UpperCAmelCase			:      Union[str, Any]			=			self.current_time
     # add the process to queue that has finished queue
     finished.append(UpperCamelCase_		)

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

   def 			SCREAMING_SNAKE_CASE  (     self   ,  _SCREAMING_SNAKE_CASE   ,  _SCREAMING_SNAKE_CASE		)						->   tuple[deque[Process], deque[Process]]:





    '''simple docstring'''




    UpperCAmelCase			:      deque[Process]			=			deque()  # sequence deque of terminated process
    # just for 1 cycle and unfinished processes will go back to queue
    for _ in range(len(UpperCamelCase_		)		):
     UpperCAmelCase			:      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(UpperCamelCase_		)
     # 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
      UpperCAmelCase			:      List[str]			=			self.current_time
      # locate the process behind the queue because it is not finished
      ready_queue.append(UpperCamelCase_		)
     else:
      # use CPU for remaining burst time
      self.current_time += cp.burst_time
      # set burst time 0 because the process is finished
      UpperCAmelCase			:      Dict			=			0
      # set the finish time
      UpperCAmelCase			:      Union[str, Any]			=			self.current_time
      # update the process' turnaround time because it is finished
      UpperCAmelCase			:      str			=			self.current_time - cp.arrival_time
      # add the process to queue that has finished queue
      finished.append(UpperCamelCase_		)

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




   def 			SCREAMING_SNAKE_CASE  (     self		)						->   deque[Process]:





    '''simple docstring'''




    for i in range(self.number_of_queues - 1		):
     UpperCAmelCase			:      List[Any]			=			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

      A:     Any										=	Process("P1", 0, 5_3)
      A:     List[Any]										=	Process("P2", 0, 1_7)
      A:     Dict										=	Process("P3", 0, 6_8)
      A:     str										=	Process("P4", 0, 2_4)
      A:     List[str]										=	3
      A:     Optional[Any]										=	[1_7, 2_5]
      A:     Any										=	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])})

      A:     List[Any]										=	Process("P1", 0, 5_3)
      A:     Any										=	Process("P2", 0, 1_7)
      A:     int										=	Process("P3", 0, 6_8)
      A:     Any										=	Process("P4", 0, 2_4)
      A:     List[Any]										=	3
      A:     List[Any]										=	[1_7, 2_5]
      A:     List[str]										=	deque([Pa, Pa, Pa, Pa])
      A:     Union[str, Any]										=	MLFQ(number_of_queues, time_slices, queue, 0)
      A:     str										=	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()}"""
      )





"""simple docstring"""
def    _snake_case		(		UpperCamelCase		:	int    ,	UpperCamelCase		:	int		):
 return 1 if input_a == input_a else 0

def    _snake_case		(		):
 assert xnor_gate(0    ,	0		) == 1
 assert xnor_gate(0    ,	1		) == 0
 assert xnor_gate(1    ,	0		) == 0
 assert xnor_gate(1    ,	1		) == 1


if __name__ == "__main__":
      print(xnor_gate(0, 0))
      print(xnor_gate(0, 1))
      print(xnor_gate(1, 0))
      print(xnor_gate(1, 1))
