
import math



class       a_   :






			def __init__(			self							, __UpperCamelCase							, __UpperCamelCase							, __UpperCamelCase							, __UpperCamelCase     ):
									_lowercase									=				x
									_lowercase									=				y
									_lowercase									=				step_size
									_lowercase									=				function_to_optimize






			def       UpperCamelCase_							(			self     ):
									return self.function(self.x							, self.y     )






			def       UpperCamelCase_							(			self     ):
									_lowercase									=				self.step_size
									return [
									    SearchProblem(__UpperCamelCase							, __UpperCamelCase							, __UpperCamelCase							, 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     ):
									return hash(str(self     )     )






			def __eq__(			self							, __UpperCamelCase     ):
									if isinstance(__UpperCamelCase							, __UpperCamelCase     ):
															return hash(str(self     )     ) == hash(str(__UpperCamelCase     )     )
									return False






			def __str__(			self     ):
									return f"""x: {self.x} y: {self.y}"""







def   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  str		,      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 = 1_00_00		,      )     ->    SearchProblem:
						_lowercase									=				search_prob
						_lowercase									=				[]  # list to store the current score at each iteration
						_lowercase									=				0
						_lowercase									=				False
						_lowercase									=				set()
						while not solution_found and iterations < max_iter:
												visited.add(SCREAMING_SNAKE_CASE_					)
												iterations += 1
												_lowercase									=				current_state.score()
												scores.append(SCREAMING_SNAKE_CASE_					)
												_lowercase									=				current_state.get_neighbors()
												_lowercase									=				-math.inf
												_lowercase									=				math.inf
												_lowercase									=				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
																		_lowercase									=				neighbor.score() - current_score
																		if find_max:  # finding max
																								# going to direction with greatest ascent
																								if change > max_change and change > 0:
																														_lowercase									=				change
																														_lowercase									=				neighbor
																		else:  # finding min
																								# to direction with greatest descent
																								if change < min_change and change < 0:
																														_lowercase									=				change
																														_lowercase									=				neighbor
												if next_state is not None:
																		# we found at least one neighbor which improved the current state
																		_lowercase									=				next_state
												else:
																		# since we have no neighbor that improves the solution we stop the search
																		_lowercase									=				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   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  str		,      SCREAMING_SNAKE_CASE_  :  Union[str, Any]					)     ->    Any:
								return (x**2) + (y**2)

		# starting the problem with initial coordinates (3, 4)
		A		:   str         =    SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
		A		:   int         =    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)
		A		:   Dict         =    SearchProblem(x=12, y=47, step_size=1, function_to_optimize=test_fa)
		A		:   int         =    hill_climbing(
		    prob, find_max=False, max_x=100, 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   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  Dict		,      SCREAMING_SNAKE_CASE_  :  str					)     ->    Any:
								return (3 * x**2) - (6 * y)

		A		:   str         =    SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
		A		:   Optional[int]         =    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()}'
		)

def   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  int					)     ->    int:
						return n * (2 * n - 1)




def   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  int					)     ->    bool:
						_lowercase									=				(1 + 24 * n) ** 0.5
						return ((1 + root) / 6) % 1 == 0




def   UpperCamelCase__     (    SCREAMING_SNAKE_CASE_  :  int = 1_44					)     ->    int:
						_lowercase									=				start
						_lowercase									=				hexagonal_num(SCREAMING_SNAKE_CASE_					)
						while not is_pentagonal(SCREAMING_SNAKE_CASE_					):
												n += 1
												_lowercase									=				hexagonal_num(SCREAMING_SNAKE_CASE_					)
						return num


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