"""simple docstring"""







import numpy

class 		UpperCamelCase      :



				def __init__(self    :				Optional[int]     ,  _A    :				numpy.ndarray     ,  _A    :				numpy.ndarray)   ->     None:
					__snake_case      :							Tuple						=			input_array

					# Random initial weights are assigned where first argument is the
					# number of nodes in previous layer and second argument is the
					# number of nodes in the next layer.

					# Random initial weights are assigned.
					# self.input_array.shape[1] is used to represent number of nodes in input layer.
					# First hidden layer consists of 4 nodes.
					__snake_case      :							List[str]						=			numpy.random.rand(
					    self.input_array.shape[1]     ,  4)

					# Random initial values for the first hidden layer.
					# First hidden layer has 4 nodes.
					# Second hidden layer has 3 nodes.
					__snake_case      :							Optional[Any]						=			numpy.random.rand(
					    4     ,  3)

					# Random initial values for the second hidden layer.
					# Second hidden layer has 3 nodes.
					# Output layer has 1 node.
					__snake_case      :							Optional[int]						=			numpy.random.rand(3     ,  1)

					# Real output values provided.
					__snake_case      :							Optional[Any]						=			output_array

					# Predicted output values by the neural network.
					# Predicted_output array initially consists of zeroes.
					__snake_case      :							List[str]						=			numpy.zeros(output_array.shape)



				def  _lowercase					(self    :				Optional[int])   ->     numpy.ndarray:
					__snake_case      :							List[str]						=			sigmoid(
					    numpy.dot(self.input_array     ,  self.input_layer_and_first_hidden_layer_weights))

					# layer_between_first_hidden_layer_and_second_hidden_layer is the layer
					# connecting the first hidden set of nodes with the second hidden set of nodes.
					__snake_case      :							List[str]						=			sigmoid(
					    numpy.dot(
					        self.layer_between_input_and_first_hidden_layer     ,  self.first_hidden_layer_and_second_hidden_layer_weights     ,  ))

					# layer_between_second_hidden_layer_and_output is the layer connecting
					# second hidden layer with the output node.
					__snake_case      :							str						=			sigmoid(
					    numpy.dot(
					        self.layer_between_first_hidden_layer_and_second_hidden_layer     ,  self.second_hidden_layer_and_output_layer_weights     ,  ))

					return self.layer_between_second_hidden_layer_and_output



				def  _lowercase					(self    :				Dict)   ->     None:
					__snake_case      :							int						=			numpy.dot(
					    self.layer_between_first_hidden_layer_and_second_hidden_layer.T     ,  2
					    * (self.output_array - self.predicted_output)
					    * sigmoid_derivative(self.predicted_output)     ,  )
					__snake_case      :							int						=			numpy.dot(
					    self.layer_between_input_and_first_hidden_layer.T     ,  numpy.dot(
					        2
					        * (self.output_array - self.predicted_output)
					        * sigmoid_derivative(self.predicted_output)     ,  self.second_hidden_layer_and_output_layer_weights.T     ,  )
					    * sigmoid_derivative(
					        self.layer_between_first_hidden_layer_and_second_hidden_layer)     ,  )
					__snake_case      :							int						=			numpy.dot(
					    self.input_array.T     ,  numpy.dot(
					        numpy.dot(
					            2
					            * (self.output_array - self.predicted_output)
					            * sigmoid_derivative(self.predicted_output)     ,  self.second_hidden_layer_and_output_layer_weights.T     ,  )
					        * sigmoid_derivative(
					            self.layer_between_first_hidden_layer_and_second_hidden_layer)     ,  self.first_hidden_layer_and_second_hidden_layer_weights.T     ,  )
					    * sigmoid_derivative(self.layer_between_input_and_first_hidden_layer)     ,  )

					self.input_layer_and_first_hidden_layer_weights += (
					    updated_input_layer_and_first_hidden_layer_weights
					)
					self.first_hidden_layer_and_second_hidden_layer_weights += (
					    updated_first_hidden_layer_and_second_hidden_layer_weights
					)
					self.second_hidden_layer_and_output_layer_weights += (
					    updated_second_hidden_layer_and_output_layer_weights
					)



				def  _lowercase					(self    :				Optional[int]     ,  _A    :				numpy.ndarray     ,  _A    :				int     ,  _A    :				bool)   ->     None:
					for iteration in range(1     ,  iterations + 1):
						__snake_case      :							List[str]						=			self.feedforward()
						self.back_propagation()
						if give_loss:
							__snake_case      :							Any						=			numpy.mean(numpy.square(output - self.feedforward()))
							print(f"Iteration {iteration} Loss: {loss}")






				def  _lowercase					(self    :				List[Any]     ,  _A    :				numpy.ndarray)   ->     int:
					__snake_case      :							Any						=			input_arr

					__snake_case      :							Any						=			sigmoid(
					    numpy.dot(self.array     ,  self.input_layer_and_first_hidden_layer_weights))

					__snake_case      :							List[str]						=			sigmoid(
					    numpy.dot(
					        self.layer_between_input_and_first_hidden_layer     ,  self.first_hidden_layer_and_second_hidden_layer_weights     ,  ))

					__snake_case      :							List[Any]						=			sigmoid(
					    numpy.dot(
					        self.layer_between_first_hidden_layer_and_second_hidden_layer     ,  self.second_hidden_layer_and_output_layer_weights     ,  ))

					return int(self.layer_between_second_hidden_layer_and_output > 0.6)







def   __UpperCAmelCase    (   UpperCAmelCase_   :    numpy.ndarray  )							->      numpy.ndarray:

	'''simple docstring'''





	return 1 / (1 + numpy.exp(-value  ))
def   __UpperCAmelCase    (   UpperCAmelCase_   :    numpy.ndarray  )							->      numpy.ndarray:

	'''simple docstring'''





	return (value) * (1 - (value))
def   __UpperCAmelCase    (   )							->      int:

	'''simple docstring'''





	__snake_case      :							Tuple						=			numpy.array(
	    (
	        [0, 0, 0],
	        [0, 0, 1],
	        [0, 1, 0],
	        [0, 1, 1],
	        [1, 0, 0],
	        [1, 0, 1],
	        [1, 1, 0],
	        [1, 1, 1],
	    )      ,							dtype=numpy.floataa      ,							)

	# True output values for the given input values.
	__snake_case      :							Tuple						=			numpy.array(([0], [1], [1], [0], [1], [0], [0], [1])      ,							dtype=numpy.floataa  )

	# Calling neural network class.
	__snake_case      :							str						=			TwoHiddenLayerNeuralNetwork(
	    input_array=UpperCAmelCase_      ,							output_array=UpperCAmelCase_  )

	# Calling training function.
	# Set give_loss to True if you want to see loss in every iteration.
	neural_network.train(output=UpperCAmelCase_      ,							iterations=10      ,							give_loss=UpperCAmelCase_  )

	return neural_network.predict(numpy.array(([1, 1, 1])      ,							dtype=numpy.floataa  )  )


if __name__ == "__main__":
	example()






"""simple docstring"""







def   __UpperCAmelCase    (   UpperCAmelCase_   :    list      ,							UpperCAmelCase_   :    int      ,							UpperCAmelCase_   :    int = 0      ,							UpperCAmelCase_   :    int = 0  )							->      int:

	'''simple docstring'''





	__snake_case      :							str						=			right or len(UpperCAmelCase_  ) - 1
	if left > right:
		return -1
	elif list_data[left] == key:
		return left
	elif list_data[right] == key:
		return right
	else:
		return search(UpperCAmelCase_      ,							UpperCAmelCase_      ,							left + 1      ,							right - 1  )


if __name__ == "__main__":
	import doctest

	doctest.testmod()





