
import string

import numpy




def       _SCREAMING_SNAKE_CASE   (						_lowerCamelCase					:     int		,    _lowerCamelCase					:     int)   ->       int:






							'''simple docstring'''





							return b if a == 0 else greatest_common_divisor(b % a		,    _lowerCamelCase)




class 					lowerCamelCase__				:




	'''simple docstring'''




	_A								=	string.ascii_uppercase + string.digits
	# This cipher takes alphanumerics into account
	# i.e. a total of 36 characters

	# take x and return x % len(key_string)
	_A								=	numpy.vectorize(lambda __lowercase: x % 3_6)

	_A								=	numpy.vectorize(lowercase__)







	def __init__(   self						:str	,  a						:numpy.ndarray		)						->					None:
								__UpperCamelCase      :  Dict       =   self.modulus(SCREAMING_SNAKE_CASE_		)  # mod36 calc's on the encrypt key
								self.check_determinant()  # validate the determinant of the encryption key
								__UpperCamelCase      :  Dict       =   encrypt_key.shape[0]







	def   _lowerCamelCase							(   self						:Optional[int]	,  a						:str		)						->					int:
								return self.key_string.index(SCREAMING_SNAKE_CASE_		)







	def   _lowerCamelCase							(   self						:Optional[Any]	,  a						:int		)						->					str:
								return self.key_string[round(SCREAMING_SNAKE_CASE_		)]







	def   _lowerCamelCase							(   self						:int		)						->					None:
								__UpperCamelCase      :  Dict       =   round(numpy.linalg.det(self.encrypt_key		)		)

								if det < 0:
															__UpperCamelCase      :  List[str]       =   det % len(self.key_string		)

								__UpperCamelCase      :  Optional[int]       =   len(self.key_string		)
								if greatest_common_divisor(SCREAMING_SNAKE_CASE_	,  len(self.key_string		)		) != 1:
															__UpperCamelCase      :  Optional[int]       =   (
															    f'determinant modular {req_l} of encryption key({det}) '
															    f'is not co prime w.r.t {req_l}.\nTry another key.'
															)
															raise ValueError(SCREAMING_SNAKE_CASE_		)







	def   _lowerCamelCase							(   self						:List[str]	,  a						:str		)						->					str:
								__UpperCamelCase      :  str       =   [char for char in text.upper() if char in self.key_string]

								__UpperCamelCase      :  Optional[Any]       =   chars[-1]
								while len(SCREAMING_SNAKE_CASE_		) % self.break_key != 0:
															chars.append(SCREAMING_SNAKE_CASE_		)

								return "".join(SCREAMING_SNAKE_CASE_		)







	def   _lowerCamelCase							(   self						:Optional[int]	,  a						:str		)						->					str:
								__UpperCamelCase      :  Union[str, Any]       =   self.process_text(text.upper()		)
								__UpperCamelCase      :  List[Any]       =   ""

								for i in range(0	,  len(SCREAMING_SNAKE_CASE_		) - self.break_key + 1	,  self.break_key		):
															__UpperCamelCase      :  List[str]       =   text[i : i + self.break_key]
															__UpperCamelCase      :  Tuple       =   [self.replace_letters(SCREAMING_SNAKE_CASE_		) for char in batch]
															__UpperCamelCase      :  Union[str, Any]       =   numpy.array([vec]		).T
															__UpperCamelCase      :  str       =   self.modulus(self.encrypt_key.dot(SCREAMING_SNAKE_CASE_		)		).T.tolist()[
															    0
															]
															__UpperCamelCase      :  str       =   "".join(
															    self.replace_digits(SCREAMING_SNAKE_CASE_		) for num in batch_encrypted		)
															encrypted += encrypted_batch

								return encrypted







	def   _lowerCamelCase							(   self						:Tuple		)						->					numpy.ndarray:
								__UpperCamelCase      :  Dict       =   round(numpy.linalg.det(self.encrypt_key		)		)

								if det < 0:
															__UpperCamelCase      :  Optional[Any]       =   det % len(self.key_string		)
								__UpperCamelCase      :  Tuple       =   None
								for i in range(len(self.key_string		)		):
															if (det * i) % len(self.key_string		) == 1:
																						__UpperCamelCase      :  List[Any]       =   i
																						break

								__UpperCamelCase      :  List[Any]       =   (
								    det_inv
								    * numpy.linalg.det(self.encrypt_key		)
								    * numpy.linalg.inv(self.encrypt_key		)
								)

								return self.to_int(self.modulus(SCREAMING_SNAKE_CASE_		)		)







	def   _lowerCamelCase							(   self						:List[str]	,  a						:str		)						->					str:
								__UpperCamelCase      :  str       =   self.make_decrypt_key()
								__UpperCamelCase      :  Tuple       =   self.process_text(text.upper()		)
								__UpperCamelCase      :  List[Any]       =   ""

								for i in range(0	,  len(SCREAMING_SNAKE_CASE_		) - self.break_key + 1	,  self.break_key		):
															__UpperCamelCase      :  int       =   text[i : i + self.break_key]
															__UpperCamelCase      :  Tuple       =   [self.replace_letters(SCREAMING_SNAKE_CASE_		) for char in batch]
															__UpperCamelCase      :  Dict       =   numpy.array([vec]		).T
															__UpperCamelCase      :  Union[str, Any]       =   self.modulus(decrypt_key.dot(SCREAMING_SNAKE_CASE_		)		).T.tolist()[0]
															__UpperCamelCase      :  List[Any]       =   "".join(
															    self.replace_digits(SCREAMING_SNAKE_CASE_		) for num in batch_decrypted		)
															decrypted += decrypted_batch

								return decrypted




def       _SCREAMING_SNAKE_CASE   (						)   ->       None:






							'''simple docstring'''





							__UpperCamelCase      :  int       =   int(input("Enter the order of the encryption key: "))
							__UpperCamelCase      :  int       =   []

							print("Enter each row of the encryption key with space separated integers")
							for _ in range(_lowerCamelCase):
														__UpperCamelCase      :  str       =   [int(_lowerCamelCase) for x in input().split()]
														hill_matrix.append(_lowerCamelCase)

							__UpperCamelCase      :  Tuple       =   HillCipher(numpy.array(_lowerCamelCase))

							print("Would you like to encrypt or decrypt some text? (1 or 2)")
							__UpperCamelCase      :  List[Any]       =   input("\n1. Encrypt\n2. Decrypt\n")
							if option == "1":
														__UpperCamelCase      :  int       =   input("What text would you like to encrypt?: ")
														print("Your encrypted text is:")
														print(hc.encrypt(_lowerCamelCase))
							elif option == "2":
														__UpperCamelCase      :  int       =   input("What text would you like to decrypt?: ")
														print("Your decrypted text is:")
														print(hc.decrypt(_lowerCamelCase))


if __name__ == "__main__":
		import doctest

		doctest.testmod()

		main()

"""simple docstring"""






from collections import namedtuple

UpperCAmelCase        =				namedtuple("""from_to""", """from_ to""")

UpperCAmelCase        =				{
    """cubicmeter""": from_to(1, 1),
    """litre""": from_to(0.001, 1_0_0_0),
    """kilolitre""": from_to(1, 1),
    """gallon""": from_to(0.00_454, 264.172),
    """cubicyard""": from_to(0.76_455, 1.30_795),
    """cubicfoot""": from_to(0.028, 35.3_147),
    """cup""": from_to(0.000_236_588, 4_226.75),
}




def __magic_name__	(				_lowerCamelCase:		float,					_lowerCamelCase:		str,					_lowerCamelCase:		str			)					->						float:

	'''simple docstring'''




	if from_type not in METRIC_CONVERSION:
		raise ValueError(
		    F"""Invalid 'from_type' value: {from_type!r}  Supported values are:\n"""
		    + ''', '''.join(_lowerCamelCase			)			)
	if to_type not in METRIC_CONVERSION:
		raise ValueError(
		    F"""Invalid 'to_type' value: {to_type!r}.  Supported values are:\n"""
		    + ''', '''.join(_lowerCamelCase			)			)
	return value * METRIC_CONVERSION[from_type].from_ * METRIC_CONVERSION[to_type].to


if __name__ == "__main__":
					import doctest

					doctest.testmod()


