





"""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"""






             __SCREAMING_SNAKE_CASE   :List[str]						=  process_name  # process name
             __SCREAMING_SNAKE_CASE   :Optional[Any]						=  arrival_time  # arrival time of the process
             # completion time of finished process or last interrupted time
             __SCREAMING_SNAKE_CASE   :Union[str, Any]						=  arrival_time
             __SCREAMING_SNAKE_CASE   :List[str]						=  burst_time  # remaining burst time
             __SCREAMING_SNAKE_CASE   :int						=  0  # total time of the process wait in ready queue
             __SCREAMING_SNAKE_CASE   :List[Any]						=  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"""






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




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





             """simple docstring"""






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




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      list[int]:





             """simple docstring"""






             __SCREAMING_SNAKE_CASE   :List[Any]						=  []
             for i in range(len(SCREAMING_SNAKE_CASE__							)							):
                   waiting_times.append(queue[i].waiting_time							)
             return waiting_times




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      list[int]:





             """simple docstring"""






             __SCREAMING_SNAKE_CASE   :Dict						=  []
             for i in range(len(SCREAMING_SNAKE_CASE__							)							):
                   turnaround_times.append(queue[i].turnaround_time							)
             return turnaround_times




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      list[int]:





             """simple docstring"""






             __SCREAMING_SNAKE_CASE   :Optional[int]						=  []
             for i in range(len(SCREAMING_SNAKE_CASE__							)							):
                   completion_times.append(queue[i].stop_time							)
             return completion_times




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      list[int]:





             """simple docstring"""






             return [q.burst_time for q in queue]




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      int:





             """simple docstring"""






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




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__							)			->      deque[Process]:





             """simple docstring"""






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

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




       def     _UpperCamelCase     (						self		,SCREAMING_SNAKE_CASE__		,SCREAMING_SNAKE_CASE__							)			->      tuple[deque[Process], deque[Process]]:





             """simple docstring"""






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

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




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





             """simple docstring"""






             for i in range(self.number_of_queues - 1							):
                   __SCREAMING_SNAKE_CASE				,__SCREAMING_SNAKE_CASE   :Tuple						=  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

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

  lowerCamelCase_								=		Process("P1", 0, 5_3)
  lowerCamelCase_								=		Process("P2", 0, 1_7)
  lowerCamelCase_								=		Process("P3", 0, 6_8)
  lowerCamelCase_								=		Process("P4", 0, 2_4)
  lowerCamelCase_								=		3
  lowerCamelCase_								=		[1_7, 2_5]
  lowerCamelCase_								=		deque([Pa, Pa, Pa, Pa])
  lowerCamelCase_								=		MLFQ(number_of_queues, time_slices, queue, 0)
  lowerCamelCase_								=		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"""
from collections.abc import Callable

import numpy as np



def      __lowerCamelCase   (							a_     :		Callable ,   a_     :		float ,   a_     :		float ,   a_     :		float ,   a_     :		float							)			->      np.ndarray:
      __SCREAMING_SNAKE_CASE   :List[Any]						=  int(np.ceil((x_end - xa) / step_size							)							)
      __SCREAMING_SNAKE_CASE   :Optional[Any]						=  np.zeros((n + 1,)							)
      __SCREAMING_SNAKE_CASE   :int						=  ya
      __SCREAMING_SNAKE_CASE   :str						=  xa

      for k in range(a_							):
            __SCREAMING_SNAKE_CASE   :Optional[int]						=  y[k] + step_size * ode_func(a_ ,   y[k]							)
            x += step_size

      return y


if __name__ == "__main__":
  import doctest

  doctest.testmod()