

'''simple docstring'''






from importlib import import_module

from .logging import get_logger


lowerCAmelCase__   		=      get_logger(__name__)






class      lowercase_      :




  """simple docstring"""




  def __init__( self  :	Union[str, Any]   ,lowercase__  :	Dict   ,lowercase__  :	Union[str, Any]=None     ):
   __lowercase				    =					attrs or []
   if module is not None:
    for key in module.__dict__:
     if key in attrs or not key.startswith('''__'''     ):
      setattr(self   ,lowercase__   ,getattr(lowercase__   ,lowercase__     )     )
   __lowercase				    =					module._original_module if isinstance(lowercase__   ,_PatchedModuleObj     ) else module






class      lowercase_      :




  """simple docstring"""




  SCREAMING_SNAKE_CASE       :    str							     =     []






  def __init__( self  :	Tuple   ,lowercase__  :	Dict   ,lowercase__  :	str   ,lowercase__  :	List[str]   ,lowercase__  :	Any=None     ):
   __lowercase				    =					obj
   __lowercase				    =					target
   __lowercase				    =					new
   __lowercase				    =					target.split('''.'''     )[0]
   __lowercase				    =					{}
   __lowercase				    =					attrs or []






  def __enter__( self  :	Union[str, Any]     ):
   *__lowercase    ,      __lowercase				    =					self.target.split('''.'''     )

   # Patch modules:
   # it's used to patch attributes of submodules like "os.path.join";
   # in this case we need to patch "os" and "os.path"

   for i in range(len(lowercase__     )     ):
    try:
     __lowercase				    =					import_module('''.'''.join(submodules[: i + 1]     )     )
    except ModuleNotFoundError:
     continue
    # We iterate over all the globals in self.obj in case we find "os" or "os.path"
    for attr in self.obj.__dir__():
     __lowercase				    =					getattr(self.obj   ,lowercase__     )
     # We don't check for the name of the global, but rather if its value *is* "os" or "os.path".
     # This allows to patch renamed modules like "from os import path as ospath".
     if obj_attr is submodule or (
         (isinstance(lowercase__   ,_PatchedModuleObj     ) and obj_attr._original_module is submodule)
     ):
      __lowercase				    =					obj_attr
      # patch at top level
      setattr(self.obj   ,lowercase__   ,_PatchedModuleObj(lowercase__   ,attrs=self.attrs     )     )
      __lowercase				    =					getattr(self.obj   ,lowercase__     )
      # construct lower levels patches
      for key in submodules[i + 1 :]:
       setattr(lowercase__   ,lowercase__   ,_PatchedModuleObj(getattr(lowercase__   ,lowercase__   ,lowercase__     )   ,attrs=self.attrs     )     )
       __lowercase				    =					getattr(lowercase__   ,lowercase__     )
      # finally set the target attribute
      setattr(lowercase__   ,lowercase__   ,self.new     )

        # Patch attribute itself:
        # it's used for builtins like "open",
        # and also to patch "os.path.join" we may also need to patch "join"
        # itself if it was imported as "from os.path import join".

   if submodules:  # if it's an attribute of a submodule like "os.path.join"
    try:
     __lowercase				    =					getattr(import_module('''.'''.join(lowercase__     )     )   ,lowercase__     )
    except (AttributeError, ModuleNotFoundError):
     return
    # We iterate over all the globals in self.obj in case we find "os.path.join"
    for attr in self.obj.__dir__():
     # We don't check for the name of the global, but rather if its value *is* "os.path.join".
     # This allows to patch renamed attributes like "from os.path import join as pjoin".
     if getattr(self.obj   ,lowercase__     ) is attr_value:
      __lowercase				    =					getattr(self.obj   ,lowercase__     )
      setattr(self.obj   ,lowercase__   ,self.new     )
   elif target_attr in globals()["__builtins__"]:  # if it'a s builtin like "open"
    __lowercase				    =					globals()['''__builtins__'''][target_attr]
    setattr(self.obj   ,lowercase__   ,self.new     )
   else:
    raise RuntimeError(F"Tried to patch attribute {target_attr} instead of a submodule."     )






  def __exit__( self  :	Tuple   ,*lowercase__  :	Any     ):
   for attr in list(self.original     ):
    setattr(self.obj   ,lowercase__   ,self.original.pop(lowercase__     )     )






  def    SCREAMING_SNAKE_CASE ( self  :	int     ):
   self.__enter__()
   self._active_patches.append(self     )






  def    SCREAMING_SNAKE_CASE ( self  :	Dict     ):
   try:
    self._active_patches.remove(self     )
   except ValueError:
    # If the patch hasn't been started this will fail
    return None

   return self.__exit__()


from sympy import diff, lambdify, symbols
from sympy.functions import *  # noqa: F403




def    lowerCAmelCase_  (		lowercase:				str	,       lowercase:				complex	,       lowercase:				str = "x"	,       lowercase:				float = 10**-10	,       lowercase:				int = 1	,       )     ->					complex:







 '''simple docstring'''
 _UpperCamelCase:  Any    						=			symbols(lowercase		)
 _UpperCamelCase:  str    						=			lambdify(lowercase	,       lowercase		)
 _UpperCamelCase:  str    						=			lambdify(lowercase	,       diff(lowercase	,       lowercase		)		)

 _UpperCamelCase:  Optional[int]    						=			starting_point

 while True:
  if diff_function(lowercase		) != 0:
   _UpperCamelCase:  int    						=			prev_guess - multiplicity * func(lowercase		) / diff_function(
       lowercase		)
  else:
   raise ZeroDivisionError('''Could not find root'''		) from None

  # Precision is checked by comparing the difference of consecutive guesses
  if abs(next_guess - prev_guess		) < precision:
   return next_guess

  _UpperCamelCase:  Any    						=			next_guess


# Let's Execute
if __name__ == "__main__":
  # Find root of trigonometric function
  # Find value of pi
  print(f"""The root of sin(x) = 0 is {newton_raphson('sin(x)', 2)}""")

  # Find root of polynomial
  # Find fourth Root of 5
  print(f"""The root of x**4 - 5 = 0 is {newton_raphson('x**4 -5', 0.4 +5J)}""")

  # Find value of e
  print(
      '''The root of log(y) - 1 = 0 is ''',
      f"""{newton_raphson('log(y) - 1', 2, variable='y')}""",
  )

  # Exponential Roots
  print(
      '''The root of exp(x) - 1 = 0 is''',
      f"""{newton_raphson('exp(x) - 1', 1_0, precision=0.0_0_5)}""",
  )

  # Find root of cos(x)
  print(f"""The root of cos(x) = 0 is {newton_raphson('cos(x)', 0)}""")