#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon Sep 2 21:37:10 2024 @author: amriksen """ import numpy as np import matplotlib.pyplot as plt def my_Newton_Method_ComplexPlane(z, func, dfunc, order=1.0, max_iter=100, tol=1e-16): for i in range(max_iter): f_z = func(z) df_z = dfunc(z) # Check if the function or derivative evaluation returned None or if derivative is too small if f_z is None or df_z is None: return None # Avoid division by a very small number if np.abs(df_z) < tol: # Perturb the current z slightly to avoid division by a small df_z z = z + tol # You can tweak this perturbation strategy as needed df_z = dfunc(z) if np.abs(df_z) < tol: # If perturbation doesn't help, return None or break return None # Update z using Newton's method z_next = z - order * f_z / df_z # Check for convergence if abs(z_next - z) < tol: return z_next z = z_next # Return the last value of z if it doesn't converge return z def my_Relaxed_Newton_Method_ComplexPlane(z, func, dfunc, order, max_iter=100, tol=1e-16): # z_next = z - k*f_z/df_z for i in range(max_iter): f_z = func(z) df_z = dfunc(z) # Check if the function or derivative evaluation returned None or if derivative is too small if f_z is None or df_z is None: return None # Avoid division by a very small number if np.abs(df_z) < tol: # Perturb the current z slightly to avoid division by a small df_z z = z + tol # You can tweak this perturbation strategy as needed df_z = dfunc(z) if np.abs(df_z) < tol: # If perturbation doesn't help, return None or break return None z_next = z - order * f_z / df_z # Check for NaN or Inf in the result if np.isnan(z_next) or np.isinf(z_next): return None if abs(z_next - z) < tol: break z = z_next return z def my_Newton_Method_Multiple_Roots(z, func, dfunc, d2func, max_iter=50, tol=1e-6): """ Newton's method adjusted for multiple roots using the second derivative. :param z: Initial guess :param func: Function to find roots for :param dfunc: First derivative of the function :param d2func: Second derivative of the function :param max_iter: Maximum number of iterations :param tol: Tolerance for convergence :return: Approximation of the root """ for i in range(max_iter): f_z = func(z) df_z = dfunc(z) d2f_z = d2func(z) # Check if any function evaluation returned None if f_z is None or df_z is None or d2f_z is None: return None # Avoid division by zero or small numbers denominator = df_z**2 - f_z * d2f_z if np.abs(denominator) < tol: return None # Modified Newton's method for multiple roots z_next = z - (f_z * df_z) / denominator # Check for NaN or Inf in the result if np.isnan(z_next) or np.isinf(z_next): return None if abs(z_next - z) < tol: return z_next z = z_next return z def find_root_index(z, roots, tol=1e-6): if z is None: return len(roots) for i, root in enumerate(roots): if abs(z - root) < tol: return i return len(roots)