


'''simple docstring'''



import math





class 							__UpperCamelCase       :




	def __init__(     self		,       __a		,       __a		,       __a		,       __a							):

						'''simple docstring'''





						__a    : Union[str, Any]      					=						x
						__a    : List[str]      					=						y
						__a    : Union[str, Any]      					=						step_size
						__a    : Tuple      					=						function_to_optimize




	def    __UpperCAmelCase							(     self							):

						'''simple docstring'''





						return self.function(self.x		,       self.y							)




	def    __UpperCAmelCase							(     self							):

						'''simple docstring'''





						__a    : Union[str, Any]      					=						self.step_size
						return [
						    SearchProblem(__a		,       __a		,       __a		,       self.function							)
						    for x, y in (
						        (self.x - step_size, self.y - step_size),
						        (self.x - step_size, self.y),
						        (self.x - step_size, self.y + step_size),
						        (self.x, self.y - step_size),
						        (self.x, self.y + step_size),
						        (self.x + step_size, self.y - step_size),
						        (self.x + step_size, self.y),
						        (self.x + step_size, self.y + step_size),
						    )
						]




	def __hash__(     self							):

						'''simple docstring'''





						return hash(str(self							)							)




	def __eq__(     self		,       __a							):

						'''simple docstring'''





						if isinstance(__a		,       __a							):
											return hash(str(self							)							) == hash(str(__a							)							)
						return False





	def __str__(     self							):

						'''simple docstring'''





						return f"""x: {self.x} y: {self.y}"""






def 						lowerCamelCase							(_SCREAMING_SNAKE_CASE   :     Union[str, Any]		,   _SCREAMING_SNAKE_CASE   :     bool = True		,   _SCREAMING_SNAKE_CASE   :     float = math.inf		,   _SCREAMING_SNAKE_CASE   :     float = -math.inf		,   _SCREAMING_SNAKE_CASE   :     float = math.inf		,   _SCREAMING_SNAKE_CASE   :     float = -math.inf		,   _SCREAMING_SNAKE_CASE   :     bool = False		,   _SCREAMING_SNAKE_CASE   :     int = 10_000		,   ):
					__a    : Optional[Any]      					=						search_prob
					__a    : List[Any]      					=						[]  # list to store the current score at each iteration
					__a    : Any      					=						0
					__a    : int      					=						False
					__a    : Tuple      					=						set()
					while not solution_found and iterations < max_iter:
										visited.add(_SCREAMING_SNAKE_CASE     )
										iterations += 1
										__a    : Optional[Any]      					=						current_state.score()
										scores.append(_SCREAMING_SNAKE_CASE     )
										__a    : List[Any]      					=						current_state.get_neighbors()
										__a    : Optional[Any]      					=						-math.inf
										__a    : str      					=						math.inf
										__a    : str      					=						None  # to hold the next best neighbor
										for neighbor in neighbors:
															if neighbor in visited:
																				continue  # do not want to visit the same state again
															if (
															    neighbor.x > max_x
															    or neighbor.x < min_x
															    or neighbor.y > max_y
															    or neighbor.y < min_y
															):
																				continue  # neighbor outside our bounds
															__a    : List[Any]      					=						neighbor.score() - current_score
															if find_max:  # finding max
																				# going to direction with greatest ascent
																				if change > max_change and change > 0:
																									__a    : Dict      					=						change
																									__a    : str      					=						neighbor
															else:  # finding min
																				# to direction with greatest descent
																				if change < min_change and change < 0:
																									__a    : List[str]      					=						change
																									__a    : Tuple      					=						neighbor
										if next_state is not None:
															# we found at least one neighbor which improved the current state
															__a    : Tuple      					=						next_state
										else:
															# since we have no neighbor that improves the solution we stop the search
															__a    : int      					=						True

					if visualization:
										from matplotlib import pyplot as plt

										plt.plot(range(_SCREAMING_SNAKE_CASE     )		,   _SCREAMING_SNAKE_CASE     )
										plt.xlabel('Iterations'     )
										plt.ylabel('Function values'     )
										plt.show()

					return current_state


if __name__ == "__main__":
	import doctest

	doctest.testmod()






	def 						lowerCamelCase							(_SCREAMING_SNAKE_CASE   :     Union[str, Any]		,   _SCREAMING_SNAKE_CASE   :     Union[str, Any]     ):
						return (x**2) + (y**2)

	# starting the problem with initial coordinates (3, 4)
	__lowercase			:		Dict =			SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
	__lowercase			:		Tuple =			hill_climbing(prob, find_max=False)
	print(
	    'The minimum score for f(x, y) = x^2 + y^2 found via hill climbing: '
	    f'''{local_min.score()}'''
	)

	# starting the problem with initial coordinates (12, 47)
	__lowercase			:		Optional[Any] =			SearchProblem(x=12, y=47, step_size=1, function_to_optimize=test_fa)
	__lowercase			:		Tuple =			hill_climbing(
	    prob, find_max=False, max_x=1_00, min_x=5, max_y=50, min_y=-5, visualization=True
	)
	print(
	    'The minimum score for f(x, y) = x^2 + y^2 with the domain 100 > x > 5 '
	    f'''and 50 > y > - 5 found via hill climbing: {local_min.score()}'''
	)






	def 						lowerCamelCase							(_SCREAMING_SNAKE_CASE   :     Any		,   _SCREAMING_SNAKE_CASE   :     Optional[Any]     ):
						return (3 * x**2) - (6 * y)

	__lowercase			:		Optional[Any] =			SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
	__lowercase			:		List[Any] =			hill_climbing(prob, find_max=True)




	print(
	    'The maximum score for f(x, y) = x^2 + y^2 found via hill climbing: '
	    f'''{local_min.score()}'''
	)







'''simple docstring'''



def 						lowerCamelCase							(_SCREAMING_SNAKE_CASE   :     set		,   _SCREAMING_SNAKE_CASE   :     set     ):
					assert isinstance(_SCREAMING_SNAKE_CASE		,   _SCREAMING_SNAKE_CASE     ), F"""The input value of [set_a={set_a}] is not a set"""
					assert isinstance(_SCREAMING_SNAKE_CASE		,   _SCREAMING_SNAKE_CASE     ), F"""The input value of [set_b={set_b}] is not a set"""

					return {a + b for a in set_a for b in set_b}


if __name__ == "__main__":
	from doctest import testmod

	testmod()



