






import numpy


class     __SCREAMING_SNAKE_CASE					:






						def __init__(	self     ,						_UpperCamelCase     ,						_UpperCamelCase   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						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.
												lowerCAmelCase__    						=						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.
												lowerCAmelCase__    						=						numpy.random.rand(
												    4     ,						3   )

												# Random initial values for the second hidden layer.
												# Second hidden layer has 3 nodes.
												# Output layer has 1 node.
												lowerCAmelCase__    						=						numpy.random.rand(3     ,						1   )

												# Real output values provided.
												lowerCAmelCase__    						=						output_array

												# Predicted output values by the neural network.
												# Predicted_output array initially consists of zeroes.
												lowerCAmelCase__    						=						numpy.zeros(output_array.shape   )






						def       UpperCamelCase__      (	self   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						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.
												lowerCAmelCase__    						=						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.
												lowerCAmelCase__    						=						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       UpperCamelCase__      (	self   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						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   )     ,						)
												lowerCAmelCase__    						=						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   )     ,						)
												lowerCAmelCase__    						=						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       UpperCamelCase__      (	self     ,						_UpperCamelCase     ,						_UpperCamelCase     ,						_UpperCamelCase   ):






												"""simple docstring"""
												for iteration in range(1     ,						iterations + 1   ):
																		lowerCAmelCase__    						=						self.feedforward()
																		self.back_propagation()
																		if give_loss:
																								lowerCAmelCase__    						=						numpy.mean(numpy.square(output - self.feedforward()   )   )
																								print(F"Iteration {iteration} Loss: {loss}"   )







						def       UpperCamelCase__      (	self     ,						_UpperCamelCase   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						input_arr

												lowerCAmelCase__    						=						sigmoid(
												    numpy.dot(self.array     ,						self.input_layer_and_first_hidden_layer_weights   )   )

												lowerCAmelCase__    						=						sigmoid(
												    numpy.dot(
												        self.layer_between_input_and_first_hidden_layer     ,						self.first_hidden_layer_and_second_hidden_layer_weights     ,						)   )

												lowerCAmelCase__    						=						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"""



						lowerCAmelCase__    						=						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.
						lowerCAmelCase__    						=						numpy.array(([0], [1], [1], [0], [1], [0], [0], [1])    ,       dtype=numpy.floataa		)

						# Calling neural network class.
						lowerCAmelCase__    						=						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()













from __future__ import annotations

__snake_case    :    Any         =     {
    """A""": ["""B""", """C""", """E"""],
    """B""": ["""A""", """D""", """E"""],
    """C""": ["""A""", """F""", """G"""],
    """D""": ["""B"""],
    """E""": ["""A""", """B""", """D"""],
    """F""": ["""C"""],
    """G""": ["""C"""],
}


class     __SCREAMING_SNAKE_CASE					:






						def __init__(	self     ,						_UpperCamelCase     ,						_UpperCamelCase   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						graph
												# mapping node to its parent in resulting breadth first tree
												lowerCAmelCase__    						=						{}
												lowerCAmelCase__    						=						source_vertex






						def       UpperCamelCase__      (	self   ):






												"""simple docstring"""
												lowerCAmelCase__    						=						{self.source_vertex}
												lowerCAmelCase__    						=						None
												lowerCAmelCase__    						=						[self.source_vertex]  # first in first out queue

												while queue:
																		lowerCAmelCase__    						=						queue.pop(0   )
																		for adjacent_vertex in self.graph[vertex]:
																								if adjacent_vertex not in visited:
																														visited.add(_UpperCamelCase   )
																														lowerCAmelCase__    						=						vertex
																														queue.append(_UpperCamelCase   )







						def       UpperCamelCase__      (	self     ,						_UpperCamelCase   ):






												"""simple docstring"""
												if target_vertex == self.source_vertex:
																		return self.source_vertex

												lowerCAmelCase__    						=						self.parent.get(_UpperCamelCase   )
												if target_vertex_parent is None:
																		lowerCAmelCase__    						=						(
																		    F"No path from vertex: {self.source_vertex} to vertex: {target_vertex}"
																		)
																		raise ValueError(_UpperCamelCase   )

												return self.shortest_path(_UpperCamelCase   ) + F"->{target_vertex}"


if __name__ == "__main__":
					__snake_case    :    Optional[Any]         =     Graph(graph, """G""")
					g.breath_first_search()
					print(g.shortest_path("""D"""))
					print(g.shortest_path("""G"""))
					print(g.shortest_path("""Foo"""))





