



'''simple docstring'''






import numpy as np
from matplotlib import pyplot as plt




def 					snake_case_      (  lowerCAmelCase_	)->	Optional[Any]:





       '''simple docstring'''


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



class 							lowercase :


 """simple docstring"""


 def __init__(							self						,a_						,a_=None						,a_=None						,a_=False							)	->     str:
        _UpperCAmelCase						:		str      =				units
        _UpperCAmelCase						:		Union[str, Any]      =				None
        _UpperCAmelCase						:		Optional[int]      =				None
        _UpperCAmelCase						:		List[Any]      =				activation
        if learning_rate is None:
               _UpperCAmelCase						:		Dict      =				0.3
        _UpperCAmelCase						:		str      =				learning_rate
        _UpperCAmelCase						:		str      =				is_input_layer







 def _snake_case				(							self						,a_							)	->     Union[str, Any]:
        _UpperCAmelCase						:		Any      =				np.asmatrix(np.random.normal(0						,0.5						,(self.units, back_units)							)							)
        _UpperCAmelCase						:		str      =				np.asmatrix(np.random.normal(0						,0.5						,self.units							)							).T
        if self.activation is None:
               _UpperCAmelCase						:		str      =				sigmoid







 def _snake_case				(							self							)	->     Dict:
        # activation function may be sigmoid or linear
        if self.activation == sigmoid:
               _UpperCAmelCase						:		int      =				np.dot(self.output						,(1 - self.output).T							)
               _UpperCAmelCase						:		Dict      =				np.diag(np.diag(a_							)							)
        else:
               _UpperCAmelCase						:		List[Any]      =				1
        return gradient_activation







 def _snake_case				(							self						,a_							)	->     Optional[Any]:
        _UpperCAmelCase						:		List[Any]      =				xdata
        if self.is_input_layer:
               # input layer
               _UpperCAmelCase						:		Optional[Any]      =				xdata
               _UpperCAmelCase						:		Tuple      =				xdata
               return xdata
        else:
               _UpperCAmelCase						:		str      =				np.dot(self.weight						,self.xdata							) - self.bias
               _UpperCAmelCase						:		List[str]      =				self.activation(self.wx_plus_b							)
               return self.output







 def _snake_case				(							self						,a_							)	->     List[Any]:
        _UpperCAmelCase						:		Optional[Any]      =				self.cal_gradient()  # i * i 维
        _UpperCAmelCase						:		List[Any]      =				np.asmatrix(np.dot(gradient.T						,a_							)							)

        _UpperCAmelCase						:		Optional[int]      =				np.asmatrix(self.xdata							)
        _UpperCAmelCase						:		List[str]      =				-1
        _UpperCAmelCase						:		Any      =				self.weight

        _UpperCAmelCase						:		List[Any]      =				np.dot(gradient.T						,self._gradient_weight.T							)
        _UpperCAmelCase						:		Optional[Any]      =				gradient * self._gradient_bias
        _UpperCAmelCase						:		Optional[Any]      =				np.dot(a_						,self._gradient_x							).T
        # upgrade: the Negative gradient direction
        _UpperCAmelCase						:		List[Any]      =				self.weight - self.learn_rate * self.gradient_weight
        _UpperCAmelCase						:		Any      =				self.bias - self.learn_rate * self.gradient_bias.T
        # updates the weights and bias according to learning rate (0.3 if undefined)
        return self.gradient







class 							lowercase :


 """simple docstring"""


 def __init__(							self							)	->     List[Any]:
        _UpperCAmelCase						:		Optional[Any]      =				[]
        _UpperCAmelCase						:		Optional[int]      =				[]
        _UpperCAmelCase						:		Dict      =				plt.figure()
        _UpperCAmelCase						:		Any      =				self.fig_loss.add_subplot(1						,1						,1							)







 def _snake_case				(							self						,a_							)	->     List[Any]:
        self.layers.append(a_							)







 def _snake_case				(							self							)	->     Tuple:
        for i, layer in enumerate(self.layers[:]							):
               if i < 1:
                      _UpperCAmelCase						:		Optional[Any]      =				True
               else:
                      layer.initializer(self.layers[i - 1].units							)







 def _snake_case				(							self							)	->     Tuple:
        for i, layer in enumerate(self.layers[:]							):
               print(f'''------- layer {i} -------'''							)
               print("""weight.shape """						,np.shape(layer.weight							)							)
               print("""bias.shape """						,np.shape(layer.bias							)							)







 def _snake_case				(							self						,a_						,a_						,a_						,a_							)	->     Union[str, Any]:
        _UpperCAmelCase						:		str      =				train_round
        _UpperCAmelCase						:		Dict      =				accuracy

        self.ax_loss.hlines(self.accuracy						,0						,self.train_round * 1.1							)

        _UpperCAmelCase						:		List[str]      =				np.shape(a_							)
        for _ in range(a_							):
               _UpperCAmelCase						:		List[Any]      =				0
               for row in range(x_shape[0]							):
                      _UpperCAmelCase						:		Optional[Any]      =				np.asmatrix(xdata[row, :]							).T
                      _UpperCAmelCase						:		Dict      =				np.asmatrix(ydata[row, :]							).T

                      # forward propagation
                      for layer in self.layers:
                             _UpperCAmelCase						:		Any      =				layer.forward_propagation(_xdata							)

                      _UpperCAmelCase  ,_UpperCAmelCase						:		Optional[Any]      =				self.cal_loss(_ydata						,_xdata							)
                      _UpperCAmelCase						:		Dict      =				all_loss + loss

                      # back propagation: the input_layer does not upgrade
                      for layer in self.layers[:0:-1]:
                             _UpperCAmelCase						:		int      =				layer.back_propagation(a_							)

               _UpperCAmelCase						:		Union[str, Any]      =				all_loss / x_shape[0]
               self.train_mse.append(a_							)

               self.plot_loss()

               if mse < self.accuracy:
                      print("""----达到精度----"""							)
                      return mse
        return None







 def _snake_case				(							self						,a_						,a_							)	->     List[str]:
        _UpperCAmelCase						:		List[Any]      =				np.sum(np.power((ydata - ydata_)						,2							)							)
        _UpperCAmelCase						:		Tuple      =				2 * (ydata_ - ydata)
        # vector (shape is the same as _ydata.shape)
        return self.loss, self.loss_gradient







 def _snake_case				(							self							)	->     Optional[int]:
        if self.ax_loss.lines:
               self.ax_loss.lines.remove(self.ax_loss.lines[0]							)
        self.ax_loss.plot(self.train_mse						,"""r-"""							)
        plt.ion()
        plt.xlabel("""step"""							)
        plt.ylabel("""loss"""							)
        plt.show()
        plt.pause(0.1							)







def 					snake_case_      (  )->	str:





       '''simple docstring'''


       _UpperCAmelCase						:		Optional[Any]      =				np.random.randn(10 ,     10	)
       _UpperCAmelCase						:		List[Any]      =				np.asarray(
           [
               [0.8, 0.4],
               [0.4, 0.3],
               [0.3_4, 0.4_5],
               [0.6_7, 0.3_2],
               [0.8_8, 0.6_7],
               [0.7_8, 0.7_7],
               [0.5_5, 0.6_6],
               [0.5_5, 0.4_3],
               [0.5_4, 0.1],
               [0.1, 0.5],
           ]	)
       _UpperCAmelCase						:		Optional[int]      =				BPNN()
       for i in (10, 20, 30, 2):
              model.add_layer(DenseLayer(lowerCAmelCase_	)	)
       model.build()
       model.summary()
       model.train(xdata=lowerCAmelCase_ ,     ydata=lowerCAmelCase_ ,     train_round=100 ,     accuracy=0.0_1	)


if __name__ == "__main__":
   example()








'''simple docstring'''






def 					snake_case_      (  lowerCAmelCase_	)->	tuple[int, int]:





       '''simple docstring'''


       if len(lowerCAmelCase_	) == 1:
              return a[0], a[0]
       else:
              # split A into half.
              _UpperCAmelCase						:		Union[str, Any]      =				a[: len(lowerCAmelCase_	) // 2]
              _UpperCAmelCase						:		str      =				a[len(lowerCAmelCase_	) // 2 :]

              # 2 sub problems, 1/2 of original size.
              _UpperCAmelCase  ,_UpperCAmelCase						:		str      =				max_difference(lowerCAmelCase_	)
              _UpperCAmelCase  ,_UpperCAmelCase						:		List[str]      =				max_difference(lowerCAmelCase_	)

              # get min of first and max of second
              # linear time
              _UpperCAmelCase						:		Dict      =				min(lowerCAmelCase_	)
              _UpperCAmelCase						:		List[Any]      =				max(lowerCAmelCase_	)

              # 3 cases, either (small1, big1),
              # (min_first, max_second), (small2, big2)
              # constant comparisons
              if biga - smalla > max_second - min_first and biga - smalla > biga - smalla:
                     return smalla, biga
              elif biga - smalla > max_second - min_first:
                     return smalla, biga
              else:
                     return min_first, max_second


if __name__ == "__main__":
   import doctest

   doctest.testmod()



