



import pickle

import numpy as np
from matplotlib import pyplot as plt







class     __lowerCAmelCase					:



			def __init__(		self     :						str				,	A     :						Optional[int]				,	A     :						List[str]				,	A     :						Any				,	A     :						str				,	A     :						Dict				,	A     :						Union[str, Any]=0.2				,	A     :						int=0.2)     ->					Optional[int]:



						"""simple docstring"""






						_UpperCAmelCase	 =     bp_numa
						_UpperCAmelCase	 =     bp_numa
						_UpperCAmelCase	 =     bp_numa
						_UpperCAmelCase	 =     conva_get[:2]
						_UpperCAmelCase	 =     conva_get[2]
						_UpperCAmelCase	 =     size_pa
						_UpperCAmelCase	 =     rate_w
						_UpperCAmelCase	 =     rate_t
						_UpperCAmelCase	 =     [
						    np.mat(-1 * np.random.rand(self.conva[0]				,	self.conva[0]) + 0.5)
						    for i in range(self.conva[1])
						]
						_UpperCAmelCase	 =     np.mat(-1 * np.random.rand(self.num_bpa				,	self.num_bpa) + 0.5)
						_UpperCAmelCase	 =     np.mat(-1 * np.random.rand(self.num_bpa				,	self.num_bpa) + 0.5)
						_UpperCAmelCase	 =     -2 * np.random.rand(self.conva[1]) + 1
						_UpperCAmelCase	 =     -2 * np.random.rand(self.num_bpa) + 1
						_UpperCAmelCase	 =     -2 * np.random.rand(self.num_bpa) + 1



			def 					_lowerCamelCase (		self     :						List[Any]				,	A     :						List[Any])     ->					Dict:



						"""simple docstring"""






						_UpperCAmelCase	 =     {
						    'num_bp1': self.num_bpa,
						    'num_bp2': self.num_bpa,
						    'num_bp3': self.num_bpa,
						    'conv1': self.conva,
						    'step_conv1': self.step_conva,
						    'size_pooling1': self.size_poolinga,
						    'rate_weight': self.rate_weight,
						    'rate_thre': self.rate_thre,
						    'w_conv1': self.w_conva,
						    'wkj': self.wkj,
						    'vji': self.vji,
						    'thre_conv1': self.thre_conva,
						    'thre_bp2': self.thre_bpa,
						    'thre_bp3': self.thre_bpa,
						}
						with open(A				,	'wb') as f:
									pickle.dump(A				,	A)

						print(F"Model saved： {save_path}")



			@classmethod
			def 					_lowerCamelCase (		cls     :						Tuple				,	A     :						Optional[Any])     ->					Any:



						"""simple docstring"""






						with open(A				,	'rb') as f:
									_UpperCAmelCase	 =     pickle.load(A)  # noqa: S301

						_UpperCAmelCase	 =     model_dic.get('conv1')
						conv_get.append(model_dic.get('step_conv1'))
						_UpperCAmelCase	 =     model_dic.get('size_pooling1')
						_UpperCAmelCase	 =     model_dic.get('num_bp1')
						_UpperCAmelCase	 =     model_dic.get('num_bp2')
						_UpperCAmelCase	 =     model_dic.get('num_bp3')
						_UpperCAmelCase	 =     model_dic.get('rate_weight')
						_UpperCAmelCase	 =     model_dic.get('rate_thre')
						# create model instance
						_UpperCAmelCase	 =     CNN(A				,	A				,	A				,	A				,	A				,	A				,	A)
						# modify model parameter
						_UpperCAmelCase	 =     model_dic.get('w_conv1')
						_UpperCAmelCase	 =     model_dic.get('wkj')
						_UpperCAmelCase	 =     model_dic.get('vji')
						_UpperCAmelCase	 =     model_dic.get('thre_conv1')
						_UpperCAmelCase	 =     model_dic.get('thre_bp2')
						_UpperCAmelCase	 =     model_dic.get('thre_bp3')
						return conv_ins



			def 					_lowerCamelCase (		self     :						Dict				,	A     :						int)     ->					Dict:



						"""simple docstring"""






						return 1 / (1 + np.exp(-1 * x))



			def 					_lowerCamelCase (		self     :						Tuple				,	A     :						Optional[Any])     ->					Union[str, Any]:



						"""simple docstring"""






						return round(A				,	3)



			def 					_lowerCamelCase (		self     :						Optional[int]				,	A     :						Optional[Any]				,	A     :						Optional[Any]				,	A     :						List[str]				,	A     :						str				,	A     :						str)     ->					Optional[Any]:



						"""simple docstring"""






						_UpperCAmelCase	 =     convs[0]
						_UpperCAmelCase	 =     convs[1]
						_UpperCAmelCase	 =     np.shape(A)[0]
						# get the data slice of original image data, data_focus
						_UpperCAmelCase	 =     []
						for i_focus in range(0				,	size_data - size_conv + 1				,	A):
									for j_focus in range(0				,	size_data - size_conv + 1				,	A):
												_UpperCAmelCase	 =     data[
												    i_focus : i_focus + size_conv, j_focus : j_focus + size_conv
												]
												data_focus.append(A)
        # calculate the feature map of every single kernel, and saved as list of matrix
						_UpperCAmelCase	 =     []
						_UpperCAmelCase	 =     int((size_data - size_conv) / conv_step + 1)
						for i_map in range(A):
									_UpperCAmelCase	 =     []
									for i_focus in range(len(A)):
												_UpperCAmelCase	 =     (
												    np.sum(np.multiply(data_focus[i_focus]				,	w_convs[i_map]))
												    - thre_convs[i_map]
												)
												featuremap.append(self.sig(A))
									_UpperCAmelCase	 =     np.asmatrix(A).reshape(
									    A				,	A)
									data_featuremap.append(A)

						# expanding the data slice to One dimenssion
						_UpperCAmelCase	 =     []
						for each_focus in data_focus:
									focusa_list.extend(self.Expand_Mat(A))
						_UpperCAmelCase	 =     np.asarray(A)
						return focus_list, data_featuremap



			def 					_lowerCamelCase (		self     :						Tuple				,	A     :						Tuple				,	A     :						List[str]				,	A     :						int="average_pool")     ->					str:



						"""simple docstring"""






						_UpperCAmelCase	 =     len(featuremaps[0])
						_UpperCAmelCase	 =     int(size_map / size_pooling)
						_UpperCAmelCase	 =     []
						for i_map in range(len(A)):
									_UpperCAmelCase	 =     featuremaps[i_map]
									_UpperCAmelCase	 =     []
									for i_focus in range(0				,	A				,	A):
												for j_focus in range(0				,	A				,	A):
															_UpperCAmelCase	 =     feature_map[
															    i_focus : i_focus + size_pooling,
															    j_focus : j_focus + size_pooling,
															]
															if pooling_type == "average_pool":
																		# average pooling
																		map_pooled.append(np.average(A))
															elif pooling_type == "max_pooling":
																		# max pooling
																		map_pooled.append(np.max(A))
									_UpperCAmelCase	 =     np.asmatrix(A).reshape(A				,	A)
									featuremap_pooled.append(A)
						return featuremap_pooled



			def 					_lowerCamelCase (		self     :						List[str]				,	A     :						Dict)     ->					Optional[int]:



						"""simple docstring"""






						_UpperCAmelCase	 =     []
						for i in range(len(A)):
									_UpperCAmelCase	 =     np.shape(data[i])
									_UpperCAmelCase	 =     data[i].reshape(1				,	shapes[0] * shapes[1])
									_UpperCAmelCase	 =     data_listed.getA().tolist()[0]
									data_expanded.extend(A)
						_UpperCAmelCase	 =     np.asarray(A)
						return data_expanded



			def 					_lowerCamelCase (		self     :						Optional[int]				,	A     :						Tuple)     ->					Any:



						"""simple docstring"""






						_UpperCAmelCase	 =     np.asarray(A)
						_UpperCAmelCase	 =     np.shape(A)
						_UpperCAmelCase	 =     data_mat.reshape(1				,	shapes[0] * shapes[1])
						return data_expanded



			def 					_lowerCamelCase (		self     :						int				,	A     :						Optional[int]				,	A     :						Optional[Any]				,	A     :						int				,	A     :						Any				,	A     :						Any)     ->					Optional[int]:



						"""simple docstring"""






						_UpperCAmelCase	 =     []
						_UpperCAmelCase	 =     0
						for i_map in range(A):
									_UpperCAmelCase	 =     np.ones((size_map, size_map))
									for i in range(0				,	A				,	A):
												for j in range(0				,	A				,	A):
															_UpperCAmelCase	 =     pd_pool[
															    i_pool
															]
															_UpperCAmelCase	 =     i_pool + 1
									_UpperCAmelCase	 =     np.multiply(
									    A				,	np.multiply(out_map[i_map]				,	(1 - out_map[i_map])))
									pd_all.append(A)
						return pd_all



			def 					_lowerCamelCase (		self     :						Dict				,	A     :						List[Any]				,	A     :						List[str]				,	A     :						Dict				,	A     :						Dict				,	A     :						List[str]				,	A     :						Any=bool)     ->					Any:



						"""simple docstring"""






						print('----------------------Start Training-------------------------')
						print((' - - Shape: Train_Data  ', np.shape(A)))
						print((' - - Shape: Teach_Data  ', np.shape(A)))
						_UpperCAmelCase	 =     0
						_UpperCAmelCase	 =     []
						_UpperCAmelCase	 =     1_00_00
						while rp < n_repeat and mse >= error_accuracy:
									_UpperCAmelCase	 =     0
									print(F"-------------Learning Time {rp}--------------")
									for p in range(len(A)):
												# print('------------Learning Image: %d--------------'%p)
												_UpperCAmelCase	 =     np.asmatrix(datas_train[p])
												_UpperCAmelCase	 =     np.asarray(datas_teach[p])
												_UpperCAmelCase ,  _UpperCAmelCase	 =     self.convolute(
												    A				,	self.conva				,	self.w_conva				,	self.thre_conva				,	conv_step=self.step_conva				,	)
												_UpperCAmelCase	 =     self.pooling(A				,	self.size_poolinga)
												_UpperCAmelCase	 =     np.shape(A)
												_UpperCAmelCase	 =     self._expand(A)
												_UpperCAmelCase	 =     data_bp_input

												_UpperCAmelCase	 =     np.dot(A				,	self.vji.T) - self.thre_bpa
												_UpperCAmelCase	 =     self.sig(A)
												_UpperCAmelCase	 =     np.dot(A				,	self.wkj.T) - self.thre_bpa
												_UpperCAmelCase	 =     self.sig(A)

												# --------------Model Leaning ------------------------
												# calculate error and gradient---------------
												_UpperCAmelCase	 =     np.multiply(
												    (data_teach - bp_outa)				,	np.multiply(A				,	(1 - bp_outa)))
												_UpperCAmelCase	 =     np.multiply(
												    np.dot(A				,	self.wkj)				,	np.multiply(A				,	(1 - bp_outa)))
												_UpperCAmelCase	 =     np.dot(A				,	self.vji)

												_UpperCAmelCase	 =     pd_i_all / (self.size_poolinga * self.size_poolinga)
												_UpperCAmelCase	 =     pd_conva_pooled.T.getA().tolist()
												_UpperCAmelCase	 =     self._calculate_gradient_from_pool(
												    A				,	A				,	shape_featuremapa[0]				,	shape_featuremapa[1]				,	self.size_poolinga				,	)
												# weight and threshold learning process---------
												# convolution layer
												for k_conv in range(self.conva[1]):
															_UpperCAmelCase	 =     self._expand_mat(pd_conva_all[k_conv])
															_UpperCAmelCase	 =     self.rate_weight * np.dot(A				,	A)

															_UpperCAmelCase	 =     self.w_conva[k_conv] + delta_w.reshape(
															    (self.conva[0], self.conva[0]))

															_UpperCAmelCase	 =     (
															    self.thre_conva[k_conv]
															    - np.sum(pd_conva_all[k_conv]) * self.rate_thre
															)
												# all connected layer
												_UpperCAmelCase	 =     self.wkj + pd_k_all.T * bp_outa * self.rate_weight
												_UpperCAmelCase	 =     self.vji + pd_j_all.T * bp_outa * self.rate_weight
												_UpperCAmelCase	 =     self.thre_bpa - pd_k_all * self.rate_thre
												_UpperCAmelCase	 =     self.thre_bpa - pd_j_all * self.rate_thre
												# calculate the sum error of all single image
												_UpperCAmelCase	 =     np.sum(abs(data_teach - bp_outa))
												error_count += errors
												# print('   ----Teach      ',data_teach)
												# print('   ----BP_output  ',bp_out3)
									_UpperCAmelCase	 =     rp + 1
									_UpperCAmelCase	 =     error_count / patterns
									all_mse.append(A)

						def draw_error():
									_UpperCAmelCase	 =     [error_accuracy for i in range(int(n_repeat * 1.2))]
									plt.plot(A				,	'+-')
									plt.plot(A				,	'r--')
									plt.xlabel('Learning Times')
									plt.ylabel('All_mse')
									plt.grid(A				,	alpha=0.5)
									plt.show()

						print('------------------Training Complished---------------------')
						print((' - - Training epoch: ', rp, F"     - - Mse: {mse:.6f}"))
						if draw_e:
									draw_error()
						return mse



			def 					_lowerCamelCase (		self     :						Dict				,	A     :						List[str])     ->					Optional[Any]:



						"""simple docstring"""






						_UpperCAmelCase	 =     []
						print('-------------------Start Testing-------------------------')
						print((' - - Shape: Test_Data  ', np.shape(A)))
						for p in range(len(A)):
									_UpperCAmelCase	 =     np.asmatrix(datas_test[p])
									_UpperCAmelCase ,  _UpperCAmelCase	 =     self.convolute(
									    A				,	self.conva				,	self.w_conva				,	self.thre_conva				,	conv_step=self.step_conva				,	)
									_UpperCAmelCase	 =     self.pooling(A				,	self.size_poolinga)
									_UpperCAmelCase	 =     self._expand(A)

									_UpperCAmelCase	 =     data_bp_input
									_UpperCAmelCase	 =     bp_outa * self.vji.T - self.thre_bpa
									_UpperCAmelCase	 =     self.sig(A)
									_UpperCAmelCase	 =     bp_outa * self.wkj.T - self.thre_bpa
									_UpperCAmelCase	 =     self.sig(A)
									produce_out.extend(bp_outa.getA().tolist())
						_UpperCAmelCase	 =     [list(map(self.do_round				,	A)) for each in produce_out]
						return np.asarray(A)



			def 					_lowerCamelCase (		self     :						Tuple				,	A     :						Any)     ->					List[Any]:



						"""simple docstring"""






						_UpperCAmelCase	 =     np.asmatrix(A)
						_UpperCAmelCase ,  _UpperCAmelCase	 =     self.convolute(
						    A				,	self.conva				,	self.w_conva				,	self.thre_conva				,	conv_step=self.step_conva				,	)
						_UpperCAmelCase	 =     self.pooling(A				,	self.size_poolinga)

						return data_conveda, data_pooleda


if __name__ == "__main__":
							pass





from collections import Counter
from timeit import timeit





def 							A			(  _UpperCAmelCase       :     str = ""							,     )       ->				bool:







			'''simple docstring'''
			return sum(c % 2 for c in Counter(input_str.replace(' '							,     ''					).lower()					).values()					) < 2





def 							A			(  _UpperCAmelCase       :     str = ""					)       ->				bool:







			'''simple docstring'''
			if len(_UpperCAmelCase					) == 0:
						return True
			_UpperCAmelCase	 =     input_str.replace(' '							,     ''					).lower()
			# character_freq_dict: Stores the frequency of every character in the input string
			_UpperCAmelCase	 =     {}

			for character in lower_case_input_str:
						_UpperCAmelCase	 =     character_freq_dict.get(_UpperCAmelCase							,     0					) + 1
			_UpperCAmelCase	 =     0

			for character_count in character_freq_dict.values():
						if character_count % 2:
									odd_char += 1
			if odd_char > 1:
						return False
			return True





def 							A			(  _UpperCAmelCase       :     str = ""					)       ->				None:







			'''simple docstring'''
			print('\nFor string = '							,     _UpperCAmelCase							,     ':'					)
			print(
			    '> can_string_be_rearranged_as_palindrome_counter()'							,     '\tans ='							,     can_string_be_rearranged_as_palindrome_counter(_UpperCAmelCase					)							,     '\ttime ='							,     timeit(
			        'z.can_string_be_rearranged_as_palindrome_counter(z.check_str)'							,     setup='import __main__ as z'							,     )							,     'seconds'							,     )
			print(
			    '> can_string_be_rearranged_as_palindrome()'							,     '\tans ='							,     can_string_be_rearranged_as_palindrome(_UpperCAmelCase					)							,     '\ttime ='							,     timeit(
			        'z.can_string_be_rearranged_as_palindrome(z.check_str)'							,     setup='import __main__ as z'							,     )							,     'seconds'							,     )


if __name__ == "__main__":
							UpperCAmelCase__     = input(
							    "Enter string to determine if it can be rearranged as a palindrome or not: "
							).strip()
							benchmark(check_str)
							UpperCAmelCase__     = can_string_be_rearranged_as_palindrome_counter(check_str)
							print(f"""{check_str} can {"" if status else "not "}be rearranged as a palindrome""")
