
'''simple docstring'''
import math






class 				UpperCAmelCase_			:





 def __init__(      self	,    lowercase_	,    lowercase_	,    lowercase_	,    lowercase_):
     snake_case_	:      Union[str, Any]            =  x
     snake_case_	:      int            =  y
     snake_case_	:      int            =  step_size
     snake_case_	:      Optional[Any]            =  function_to_optimize





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





 def     snake_case__						(      self):
     snake_case_	:      Any            =  self.step_size
     return [
         SearchProblem(lowercase_	,    lowercase_	,    lowercase_	,    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	,    lowercase_):
     if isinstance(lowercase_	,    lowercase_):
         return hash(str(self)) == hash(str(lowercase_))
     return False





 def __str__(      self):
     return F'x: {self.x} y: {self.y}'


def   UpperCamelCase_       (		__SCREAMING_SNAKE_CASE,						__SCREAMING_SNAKE_CASE = True,						__SCREAMING_SNAKE_CASE = math.inf,						__SCREAMING_SNAKE_CASE = -math.inf,						__SCREAMING_SNAKE_CASE = math.inf,						__SCREAMING_SNAKE_CASE = -math.inf,						__SCREAMING_SNAKE_CASE = False,						__SCREAMING_SNAKE_CASE = 1_0_0_0_0,						):
    """simple docstring"""






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






      return (x**2) + (y**2)

  # starting the problem with initial coordinates (3, 4)
  a_     =  SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
  a_     =  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_     =  SearchProblem(x=12, y=47, step_size=1, function_to_optimize=test_fa)
  a_     =  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,						__SCREAMING_SNAKE_CASE    ):
      """simple docstring"""






      return (3 * x**2) - (6 * y)

  a_     =  SearchProblem(x=3, y=4, step_size=1, function_to_optimize=test_fa)
  a_     =  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'''
from __future__ import annotations

from collections.abc import Callable

def   UpperCamelCase_       (		__SCREAMING_SNAKE_CASE,						__SCREAMING_SNAKE_CASE,						__SCREAMING_SNAKE_CASE,						__SCREAMING_SNAKE_CASE = 1_0_0,						):
    """simple docstring"""






    snake_case_	:      Optional[Any]            =  x_start
    snake_case_	:      str            =  fnc(__SCREAMING_SNAKE_CASE    )
    snake_case_	:      List[str]            =  0.0

    for _ in range(__SCREAMING_SNAKE_CASE    ):
        # Approximates small segments of curve as linear and solve
        # for trapezoidal area
        snake_case_	:      List[str]            =  (x_end - x_start) / steps + xa
        snake_case_	:      Optional[int]            =  fnc(__SCREAMING_SNAKE_CASE    )
        area += abs(fxa + fxa    ) * (xa - xa) / 2

        # Increment step
        snake_case_	:      List[Any]            =  xa
        snake_case_	:      Optional[Any]            =  fxa
    return area


if __name__ == "__main__":

  def   UpperCamelCase_       (		__SCREAMING_SNAKE_CASE    ):
      """simple docstring"""






      return x**3

  print("f(x) = x^3")
  print("The area between the curve, x = -10, x = 10 and the x axis is:")
  a_     =  10
  while i <= 10_0000:
    a_     =  trapezoidal_area(f, -5, 5, i)
    print(f"""with {i} steps: {area}""")
    i *= 10




