


import string

import numpy






def 							__lowercase   ( __lowerCAmelCase							:				int					,    __lowerCAmelCase							:				int   ):
							return b if a == 0 else greatest_common_divisor(b % a					,    __lowerCAmelCase   )







class        snake_case_   :
					UpperCAmelCase__					:    List[Any]          =			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)
					UpperCAmelCase__					:    Union[str, Any]          =			numpy.vectorize(lambda lowerCamelCase_      : x % 3_6      )

					UpperCAmelCase__					:    Optional[int]          =			numpy.vectorize(lowerCamelCase_      )
					def __init__(      self   :Optional[Any]			,__snake_case   :numpy.ndarray      )					->    None:
												a__             =     self.modulus(__snake_case      )  # mod36 calc's on the encrypt key
												self.check_determinant()  # validate the determinant of the encryption key
												a__             =     encrypt_key.shape[0]
					def  lowerCamelCase__(      self   :Any			,__snake_case   :str      )					->    int:
												return self.key_string.index(__snake_case      )
					def  lowerCamelCase__(      self   :Tuple			,__snake_case   :int      )					->    str:
												return self.key_string[round(__snake_case      )]
					def  lowerCamelCase__(      self   :List[str]      )					->    None:
												a__             =     round(numpy.linalg.det(self.encrypt_key      )      )

												if det < 0:
																			a__             =     det % len(self.key_string      )

												a__             =     len(self.key_string      )
												if greatest_common_divisor(__snake_case			,len(self.key_string      )      ) != 1:
																			a__             =     (
																			    F'determinant modular {req_l} of encryption key({det}) '
																			    F'is not co prime w.r.t {req_l}.\nTry another key.'
																			)
																			raise ValueError(__snake_case      )
					def  lowerCamelCase__(      self   :Dict			,__snake_case   :str      )					->    str:
												a__             =     [char for char in text.upper() if char in self.key_string]

												a__             =     chars[-1]
												while len(__snake_case      ) % self.break_key != 0:
																			chars.append(__snake_case      )

												return "".join(__snake_case      )
					def  lowerCamelCase__(      self   :Optional[Any]			,__snake_case   :str      )					->    str:
												a__             =     self.process_text(text.upper()      )
												a__             =     ''

												for i in range(0			,len(__snake_case      ) - self.break_key + 1			,self.break_key      ):
																			a__             =     text[i : i + self.break_key]
																			a__             =     [self.replace_letters(__snake_case      ) for char in batch]
																			a__             =     numpy.array([vec]      ).T
																			a__             =     self.modulus(self.encrypt_key.dot(__snake_case      )      ).T.tolist()[
																			    0
																			]
																			a__             =     ''.join(
																			    self.replace_digits(__snake_case      ) for num in batch_encrypted      )
																			encrypted += encrypted_batch

												return encrypted
					def  lowerCamelCase__(      self   :Optional[Any]      )					->    numpy.ndarray:
												a__             =     round(numpy.linalg.det(self.encrypt_key      )      )

												if det < 0:
																			a__             =     det % len(self.key_string      )
												a__             =     None
												for i in range(len(self.key_string      )      ):
																			if (det * i) % len(self.key_string      ) == 1:
																										a__             =     i
																										break

												a__             =     (
												    det_inv
												    * numpy.linalg.det(self.encrypt_key      )
												    * numpy.linalg.inv(self.encrypt_key      )
												)

												return self.to_int(self.modulus(__snake_case      )      )



					def  lowerCamelCase__(      self   :Tuple			,__snake_case   :str      )					->    str:
												a__             =     self.make_decrypt_key()
												a__             =     self.process_text(text.upper()      )
												a__             =     ''

												for i in range(0			,len(__snake_case      ) - self.break_key + 1			,self.break_key      ):
																			a__             =     text[i : i + self.break_key]
																			a__             =     [self.replace_letters(__snake_case      ) for char in batch]
																			a__             =     numpy.array([vec]      ).T
																			a__             =     self.modulus(decrypt_key.dot(__snake_case      )      ).T.tolist()[0]
																			a__             =     ''.join(
																			    self.replace_digits(__snake_case      ) for num in batch_decrypted      )
																			decrypted += decrypted_batch

												return decrypted






def 							__lowercase   ( ):
							a__             =     int(input('Enter the order of the encryption key: '   )   )
							a__             =     []

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

							a__             =     HillCipher(numpy.array(__lowerCAmelCase   )   )

							print('Would you like to encrypt or decrypt some text? (1 or 2)'   )
							a__             =     input('\n1. Encrypt\n2. Decrypt\n'   )
							if option == "1":
														a__             =     input('What text would you like to encrypt?: '   )
														print('Your encrypted text is:'   )
														print(hc.encrypt(__lowerCAmelCase   )   )
							elif option == "2":
														a__             =     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()








def 							__lowercase   ( __lowerCAmelCase							:				list[int]   ):
							a__             =     []
							if len(__lowerCAmelCase   ) == 1:
														return [nums.copy()]
							for _ in range(len(__lowerCAmelCase   )   ):
														a__             =     nums.pop(0   )
														a__             =     permute(__lowerCAmelCase   )
														for perm in permutations:
																					perm.append(__lowerCAmelCase   )
														result.extend(__lowerCAmelCase   )
														nums.append(__lowerCAmelCase   )
							return result






def 							__lowercase   ( __lowerCAmelCase							:				Optional[int]   ):

							def backtrack(__lowerCAmelCase							:				Any   ):
														if start == len(__lowerCAmelCase   ) - 1:
																					output.append(nums[:]   )
														else:
																					for i in range(__lowerCAmelCase					,    len(__lowerCAmelCase   )   ):
																												a__      ,					a__             =     nums[i], nums[start]
																												backtrack(start + 1   )
																												a__      ,					a__             =     nums[i], nums[start]  # backtrack

							a__             =     []
							backtrack(0   )
							return output


if __name__ == "__main__":
						import doctest

						# use res to print the data in permute2 function
						snake_case							:       Optional[Any]     			=      permutea([1, 2, 3])
						print(res)
						doctest.testmod()




