


import pickle

import numpy as np
from matplotlib import pyplot as plt

class     A__   :







    """simple docstring"""

    def __init__(			self     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case=0.2     ,   __snake_case=0.2       ):
         snake_case											=							bp_numa
         snake_case											=							bp_numa
         snake_case											=							bp_numa
         snake_case											=							conva_get[:2]
         snake_case											=							conva_get[2]
         snake_case											=							size_pa
         snake_case											=							rate_w
         snake_case											=							rate_t
         snake_case											=							[
             np.mat(-1 * np.random.rand(self.conva[0]     ,   self.conva[0]       ) + 0.5       )
             for i in range(self.conva[1]       )
         ]
         snake_case											=							np.mat(-1 * np.random.rand(self.num_bpa     ,   self.num_bpa       ) + 0.5       )
         snake_case											=							np.mat(-1 * np.random.rand(self.num_bpa     ,   self.num_bpa       ) + 0.5       )
         snake_case											=							-2 * np.random.rand(self.conva[1]       ) + 1
         snake_case											=							-2 * np.random.rand(self.num_bpa       ) + 1
         snake_case											=							-2 * np.random.rand(self.num_bpa       ) + 1
    def 						a_     (			self     ,   __snake_case       ):
         # save model dict with pickle
         snake_case											=							{
             '''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(_SCREAMING_SNAKE_CASE     ,   '''wb'''       ) as f:
              pickle.dump(_SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       )

         print(F'''Model saved： {save_path}'''       )
    @classmethod
    def 						a_     (			cls     ,   __snake_case       ):
         # read saved model
         with open(_SCREAMING_SNAKE_CASE     ,   '''rb'''       ) as f:
              snake_case											=							pickle.load(_SCREAMING_SNAKE_CASE       )  # noqa: S301

         snake_case											=							model_dic.get('''conv1'''       )
         conv_get.append(model_dic.get('''step_conv1'''       )       )
         snake_case											=							model_dic.get('''size_pooling1'''       )
         snake_case											=							model_dic.get('''num_bp1'''       )
         snake_case											=							model_dic.get('''num_bp2'''       )
         snake_case											=							model_dic.get('''num_bp3'''       )
         snake_case											=							model_dic.get('''rate_weight'''       )
         snake_case											=							model_dic.get('''rate_thre'''       )
         # create model instance
         snake_case											=							CNN(_SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       )
         # modify model parameter
         snake_case											=							model_dic.get('''w_conv1'''       )
         snake_case											=							model_dic.get('''wkj'''       )
         snake_case											=							model_dic.get('''vji'''       )
         snake_case											=							model_dic.get('''thre_conv1'''       )
         snake_case											=							model_dic.get('''thre_bp2'''       )
         snake_case											=							model_dic.get('''thre_bp3'''       )
         return conv_ins
    def 						a_     (			self     ,   __snake_case       ):
         return 1 / (1 + np.exp(-1 * x       ))
    def 						a_     (			self     ,   __snake_case       ):
         return round(_SCREAMING_SNAKE_CASE     ,   3       )
    def 						a_     (			self     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case       ):
         # convolution process
         snake_case											=							convs[0]
         snake_case											=							convs[1]
         snake_case											=							np.shape(_SCREAMING_SNAKE_CASE       )[0]
         # get the data slice of original image data, data_focus
         snake_case											=							[]
         for i_focus in range(0     ,   size_data - size_conv + 1     ,   _SCREAMING_SNAKE_CASE       ):
              for j_focus in range(0     ,   size_data - size_conv + 1     ,   _SCREAMING_SNAKE_CASE       ):
                   snake_case											=							data[
                       i_focus : i_focus + size_conv, j_focus : j_focus + size_conv
                   ]
                   data_focus.append(_SCREAMING_SNAKE_CASE       )
        # calculate the feature map of every single kernel, and saved as list of matrix
         snake_case											=							[]
         snake_case											=							int((size_data - size_conv) / conv_step + 1       )
         for i_map in range(_SCREAMING_SNAKE_CASE       ):
              snake_case											=							[]
              for i_focus in range(len(_SCREAMING_SNAKE_CASE       )       ):
                   snake_case											=							(
                       np.sum(np.multiply(data_focus[i_focus]     ,   w_convs[i_map]       )       )
                       - thre_convs[i_map]
                   )
                   featuremap.append(self.sig(_SCREAMING_SNAKE_CASE       )       )
              snake_case											=							np.asmatrix(_SCREAMING_SNAKE_CASE       ).reshape(
                  _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       )
              data_featuremap.append(_SCREAMING_SNAKE_CASE       )

         # expanding the data slice to One dimenssion
         snake_case											=							[]
         for each_focus in data_focus:
              focusa_list.extend(self.Expand_Mat(_SCREAMING_SNAKE_CASE       )       )
         snake_case											=							np.asarray(_SCREAMING_SNAKE_CASE       )
         return focus_list, data_featuremap
    def 						a_     (			self     ,   __snake_case     ,   __snake_case     ,   __snake_case="average_pool"       ):
         # pooling process
         snake_case											=							len(featuremaps[0]       )
         snake_case											=							int(size_map / size_pooling       )
         snake_case											=							[]
         for i_map in range(len(_SCREAMING_SNAKE_CASE       )       ):
              snake_case											=							featuremaps[i_map]
              snake_case											=							[]
              for i_focus in range(0     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       ):
                   for j_focus in range(0     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       ):
                        snake_case											=							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(_SCREAMING_SNAKE_CASE       )       )
                        elif pooling_type == "max_pooling":
                             # max pooling
                             map_pooled.append(np.max(_SCREAMING_SNAKE_CASE       )       )
              snake_case											=							np.asmatrix(_SCREAMING_SNAKE_CASE       ).reshape(_SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       )
              featuremap_pooled.append(_SCREAMING_SNAKE_CASE       )
         return featuremap_pooled
    def 						a_     (			self     ,   __snake_case       ):
         # expanding three dimension data to one dimension list
         snake_case											=							[]
         for i in range(len(_SCREAMING_SNAKE_CASE       )       ):
              snake_case											=							np.shape(data[i]       )
              snake_case											=							data[i].reshape(1     ,   shapes[0] * shapes[1]       )
              snake_case											=							data_listed.getA().tolist()[0]
              data_expanded.extend(_SCREAMING_SNAKE_CASE       )
         snake_case											=							np.asarray(_SCREAMING_SNAKE_CASE       )
         return data_expanded
    def 						a_     (			self     ,   __snake_case       ):
         # expanding matrix to one dimension list
         snake_case											=							np.asarray(_SCREAMING_SNAKE_CASE       )
         snake_case											=							np.shape(_SCREAMING_SNAKE_CASE       )
         snake_case											=							data_mat.reshape(1     ,   shapes[0] * shapes[1]       )
         return data_expanded
    def 						a_     (			self     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case       ):
         snake_case											=							[]
         snake_case											=							0
         for i_map in range(_SCREAMING_SNAKE_CASE       ):
              snake_case											=							np.ones((size_map, size_map)       )
              for i in range(0     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       ):
                   for j in range(0     ,   _SCREAMING_SNAKE_CASE     ,   _SCREAMING_SNAKE_CASE       ):
                        snake_case											=							pd_pool[
                            i_pool
                        ]
                        snake_case											=							i_pool + 1
              snake_case											=							np.multiply(
                  _SCREAMING_SNAKE_CASE     ,   np.multiply(out_map[i_map]     ,   (1 - out_map[i_map])       )       )
              pd_all.append(_SCREAMING_SNAKE_CASE       )
         return pd_all
    def 						a_     (			self     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case     ,   __snake_case=bool       ):
         # model traning
         print('''----------------------Start Training-------------------------'''       )
         print((''' - - Shape: Train_Data  ''', np.shape(_SCREAMING_SNAKE_CASE       ))       )
         print((''' - - Shape: Teach_Data  ''', np.shape(_SCREAMING_SNAKE_CASE       ))       )
         snake_case											=							0
         snake_case											=							[]
         snake_case											=							1_0_0_0_0
         while rp < n_repeat and mse >= error_accuracy:
              snake_case											=							0
              print(F'''-------------Learning Time {rp}--------------'''       )
              for p in range(len(_SCREAMING_SNAKE_CASE       )       ):
                   # print('------------Learning Image: %d--------------'%p)
                   snake_case											=							np.asmatrix(datas_train[p]       )
                   snake_case											=							np.asarray(datas_teach[p]       )
                   snake_case											=							self.convolute(
                       _SCREAMING_SNAKE_CASE     ,   self.conva     ,   self.w_conva     ,   self.thre_conva     ,   conv_step=self.step_conva     ,   )
                   snake_case											=							self.pooling(_SCREAMING_SNAKE_CASE     ,   self.size_poolinga       )
                   snake_case											=							np.shape(_SCREAMING_SNAKE_CASE       )
                   snake_case											=							self._expand(_SCREAMING_SNAKE_CASE       )
                   snake_case											=							data_bp_input

                   snake_case											=							np.dot(_SCREAMING_SNAKE_CASE     ,   self.vji.T       ) - self.thre_bpa
                   snake_case											=							self.sig(_SCREAMING_SNAKE_CASE       )
                   snake_case											=							np.dot(_SCREAMING_SNAKE_CASE     ,   self.wkj.T       ) - self.thre_bpa
                   snake_case											=							self.sig(_SCREAMING_SNAKE_CASE       )

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

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

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

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

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

         print('''------------------Training Complished---------------------'''       )
         print((''' - - Training epoch: ''', rp, F'''     - - Mse: {mse:.6f}''')       )
         if draw_e:
              draw_error()
         return mse
    def 						a_     (			self     ,   __snake_case       ):
         # model predict
         snake_case											=							[]
         print('''-------------------Start Testing-------------------------'''       )
         print((''' - - Shape: Test_Data  ''', np.shape(_SCREAMING_SNAKE_CASE       ))       )
         for p in range(len(_SCREAMING_SNAKE_CASE       )       ):
              snake_case											=							np.asmatrix(datas_test[p]       )
              snake_case											=							self.convolute(
                  _SCREAMING_SNAKE_CASE     ,   self.conva     ,   self.w_conva     ,   self.thre_conva     ,   conv_step=self.step_conva     ,   )
              snake_case											=							self.pooling(_SCREAMING_SNAKE_CASE     ,   self.size_poolinga       )
              snake_case											=							self._expand(_SCREAMING_SNAKE_CASE       )

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




    def 						a_     (			self     ,   __snake_case       ):
         # return the data of image after convoluting process so we can check it out
         snake_case											=							np.asmatrix(_SCREAMING_SNAKE_CASE       )
         snake_case											=							self.convolute(
             _SCREAMING_SNAKE_CASE     ,   self.conva     ,   self.w_conva     ,   self.thre_conva     ,   conv_step=self.step_conva     ,   )
         snake_case											=							self.pooling(_SCREAMING_SNAKE_CASE     ,   self.size_poolinga       )

         return data_conveda, data_pooleda


if __name__ == "__main__":
 pass










from functools import reduce

__a							     =					(
    '73167176531330624919225119674426574742355349194934'
    '96983520312774506326239578318016984801869478851843'
    '85861560789112949495459501737958331952853208805511'
    '12540698747158523863050715693290963295227443043557'
    '66896648950445244523161731856403098711121722383113'
    '62229893423380308135336276614282806444486645238749'
    '30358907296290491560440772390713810515859307960866'
    '70172427121883998797908792274921901699720888093776'
    '65727333001053367881220235421809751254540594752243'
    '52584907711670556013604839586446706324415722155397'
    '53697817977846174064955149290862569321978468622482'
    '83972241375657056057490261407972968652414535100474'
    '82166370484403199890008895243450658541227588666881'
    '16427171479924442928230863465674813919123162824586'
    '17866458359124566529476545682848912883142607690042'
    '24219022671055626321111109370544217506941658960408'
    '07198403850962455444362981230987879927244284909188'
    '84580156166097919133875499200524063689912560717606'
    '05886116467109405077541002256983155200055935729725'
    '71636269561882670428252483600823257530420752963450'
)







def lowerCamelCase__  (     _lowercase = N ):

     '''simple docstring'''


     return max(
         # mypy cannot properly interpret reduce
         int(reduce(lambda _lowercase					,		_lowercase : str(int(_lowercase ) * int(_lowercase ) )					,		n[i : i + 13] ) )
         for i in range(len(_lowercase ) - 12 ) )


if __name__ == "__main__":
     print(F"""{solution() = }""")