I have a 10 by 10 matrix, whose entries depend on a complex vairable z. I wish to evaluate the absolute value of the ratio of the largest two eigenvalues (largest by magnitude) and check for which values of z, is this absolute ratio close to 1 upto a tolerance value (let’s say 1e-10). I have a gradient-descent type of algorithm, which seems to work, but is very prone to errors and is highly starting value dependent. Is there any other method by which I can achieve this in a given domain of complex numbers (preferably quite large)? I have attached my code for the gradient-descent algorithm here:
## Now we have to design a subroutine that will calculate the ratio around a z point for different angles
num_angles = 100 #More gives a finer demarcation, keep it even
step_size = 0.1 #less gives a finer demarcation
angle_list = [2*i*np.pi/num_angles for i in range(num_angles)]
def ratio_around_z(z, angle_list, step_size,tol_points,tolerance = 1e-6): #ensure tolerance is less than c
ratio_list = []
index = 0
c_int = abs(ratio(z) - 1)
c = c_int
print("Initial dist is: ", c)
for angle in angle_list:
z_fin = z + step_size*np.exp(1j*angle)
ratio_list.append(ratio(z_fin))
for i in range(len(ratio_list)):
#print("New dist is: ", abs(ratio_list[i] - 1))
if abs(ratio_list[i] - 1) <= tolerance:
#check = 2
print("Val close to 1 found, appending in list!")
#index = i
tol_points.append(z + step_size*np.exp(1j*angle_list[i]))
if abs(ratio_list[i] - 1) < c:
#check = 1
c = abs(ratio_list[i] - 1)
print("Val less than prev dist found, changing index!")
print("New min dist is: ", c)
index = i
if c_int == c:
print("No Val close to 1 or less than prev dist!")
return z
else:
print("Angle of max gradient is: ", angle_list[index])
return z + step_size*np.exp(1j*angle_list[index])
max_steps = 500
num_steps = 500
z_int_c = 2-3j
z_int = 2-3j
i=1
step_size = 0.1
plot_points = [z_int]
dist_vals = [abs(ratio(z_int) - 1)]
tol_points = []
while num_steps > 0:
print(f"Step {i}:")
z_fin = ratio_around_z(z_int, angle_list,step_size,tol_points,tolerance = 1e-4)
if z_fin == z_int:
print(f"Stuck at minima after {i} steps!")
break
else:
plot_points.append(z_fin)
dist_vals.append(abs(ratio(z_fin) - 1))
z_int = z_fin
i+=1
num_steps -= 1
print()
I do get convergence, but seem to get stuck on a local minima mostly, with the distance from 1 around 1e-7, on which I wish to improve. I can take more number of angles and reduce step size with higher number of steps, but just wanted to ask if a better method to solve the problem exists.