from __future__ import annotations

from collections import deque




class    _UpperCamelCase      :


			"""simple docstring"""






			def __init__(   self      ,   lowerCAmelCase__						)     ->					int:

							'''simple docstring'''


							__lowercase 			=							[]
							self.adlist.append(
							    {'''value''': '''''', '''next_states''': [], '''fail_state''': 0, '''output''': []}						)

							for keyword in keywords:
											self.add_keyword(lowerCAmelCase__						)
							self.set_fail_transitions()





			def        _SCREAMING_SNAKE_CASE			(   self      ,   lowerCAmelCase__      ,   lowerCAmelCase__						)     ->					int | None:

							'''simple docstring'''


							for state in self.adlist[current_state]["next_states"]:
											if char == self.adlist[state]["value"]:
															return state
							return None





			def        _SCREAMING_SNAKE_CASE			(   self      ,   lowerCAmelCase__						)     ->					None:

							'''simple docstring'''


							__lowercase 			=							0
							for character in keyword:
											__lowercase 			=							self.find_next_state(lowerCAmelCase__      ,   lowerCAmelCase__						)
											if next_state is None:
															self.adlist.append(
															    {
															        '''value''': character,
															        '''next_states''': [],
															        '''fail_state''': 0,
															        '''output''': [],
															    }						)
															self.adlist[current_state]["next_states"].append(len(self.adlist						) - 1						)
															__lowercase 			=							len(self.adlist						) - 1
											else:
															__lowercase 			=							next_state
							self.adlist[current_state]["output"].append(lowerCAmelCase__						)





			def        _SCREAMING_SNAKE_CASE			(   self						)     ->					None:

							'''simple docstring'''


							__lowercase 			=							deque()
							for node in self.adlist[0]["next_states"]:
											q.append(lowerCAmelCase__						)
											__lowercase 			=							0
							while q:
											__lowercase 			=							q.popleft()
											for child in self.adlist[r]["next_states"]:
															q.append(lowerCAmelCase__						)
															__lowercase 			=							self.adlist[r]['''fail_state''']
															while (
															    self.find_next_state(lowerCAmelCase__      ,   self.adlist[child]['''value''']						) is None
															    and state != 0
															):
																			__lowercase 			=							self.adlist[state]['''fail_state''']
															__lowercase 			=							self.find_next_state(
															    lowerCAmelCase__      ,   self.adlist[child]['''value''']						)
															if self.adlist[child]["fail_state"] is None:
																			__lowercase 			=							0
															__lowercase 			=							(
															    self.adlist[child]['''output''']
															    + self.adlist[self.adlist[child]['''fail_state''']]['''output''']
															)





			def        _SCREAMING_SNAKE_CASE			(   self      ,   lowerCAmelCase__						)     ->					dict[str, list[int]]:

							'''simple docstring'''


							__lowercase 			=							{}  # returns a dict with keywords and list of its occurrences
							__lowercase 			=							0
							for i in range(len(lowerCAmelCase__						)						):
											while (
											    self.find_next_state(lowerCAmelCase__      ,   string[i]						) is None
											    and current_state != 0
											):
															__lowercase 			=							self.adlist[current_state]['''fail_state''']
											__lowercase 			=							self.find_next_state(lowerCAmelCase__      ,   string[i]						)
											if next_state is None:
															__lowercase 			=							0
											else:
															__lowercase 			=							next_state
															for key in self.adlist[current_state]["output"]:
																			if key not in result:
																							__lowercase 			=							[]
																			result[key].append(i - len(lowerCAmelCase__						) + 1						)
							return result


if __name__ == "__main__":
		import doctest

		doctest.testmod()
import gc
import threading
import time

import psutil
import torch




class    _UpperCamelCase      :


			"""simple docstring"""






			def __init__(   self						)     ->					str:

							'''simple docstring'''


							__lowercase 			=							psutil.Process()
							__lowercase 			=							False





			def        _SCREAMING_SNAKE_CASE			(   self						)     ->					str:

							'''simple docstring'''


							__lowercase 			=							-1

							while True:
											__lowercase 			=							max(self.process.memory_info().rss      ,   self.cpu_memory_peak						)

											# can't sleep or will not catch the peak right (this comment is here on purpose)
											if not self.peak_monitoring:
															break





			def        _SCREAMING_SNAKE_CASE			(   self						)     ->					int:

							'''simple docstring'''


							__lowercase 			=							True
							__lowercase 			=							threading.Thread(target=self.peak_monitor						)
							__lowercase 			=							True
							self.thread.start()





			def        _SCREAMING_SNAKE_CASE			(   self						)     ->					str:

							'''simple docstring'''


							__lowercase 			=							False
							self.thread.join()
							return self.cpu_memory_peak


__a  :     List[str]       =  PeakCPUMemory()





def 				UpperCAmelCase						(    ):







				"""simple docstring"""



				__lowercase 			=							{'''time''': time.time()}

				gc.collect()
				torch.cuda.empty_cache()

				# CPU mem
				__lowercase 			=							psutil.Process().memory_info().rss
				cpu_peak_tracker.start()

				# GPU mem
				for i in range(torch.cuda.device_count()							):
								__lowercase 			=							torch.cuda.memory_allocated(lowercase							)
				torch.cuda.reset_peak_memory_stats()

				return measures





def 				UpperCAmelCase						(    lowercase							):







				"""simple docstring"""



				__lowercase 			=							{'''time''': time.time() - start_measures['''time''']}

				gc.collect()
				torch.cuda.empty_cache()

				# CPU mem
				__lowercase 			=							(psutil.Process().memory_info().rss - start_measures['''cpu''']) / 2**20
				__lowercase 			=							(cpu_peak_tracker.stop() - start_measures['''cpu''']) / 2**20

				# GPU mem
				for i in range(torch.cuda.device_count()							):
								__lowercase 			=							(torch.cuda.memory_allocated(lowercase							) - start_measures[str(lowercase							)]) / 2**20
								__lowercase 			=							(torch.cuda.max_memory_allocated(lowercase							) - start_measures[str(lowercase							)]) / 2**20

				return measures





def 				UpperCAmelCase						(    lowercase							,			lowercase							):







				"""simple docstring"""



				print(F"{description}:"							)
				print(F"- Time: {measures['time']:.2f}s"							)
				for i in range(torch.cuda.device_count()							):
								print(F"- GPU {i} allocated: {measures[str(lowercase							)]:.2f}MiB"							)
								__lowercase 			=							measures[F"{i}-peak"]
								print(F"- GPU {i} peak: {peak:.2f}MiB"							)
				print(F"- CPU RAM allocated: {measures['cpu']:.2f}MiB"							)
				print(F"- CPU RAM peak: {measures['cpu-peak']:.2f}MiB"							)