import numpy as np 

a = -1
b = 2.3
z = 2 + 3j

# type of a variable 
print(type(a))
print(type(b))
print(type(z))

# real and imaginary parts 
print(np.real(z))
print(np.imag(z))

# conjugation
print(z)
print(np.conjugate(z))

# plot the conjugates 
import matplotlib.pyplot as plt

# make figure
fig = plt.figure()

# get the axes
ax = plt.axes()

# here we use "scatter" to plot individual points on the 2D plane
ax.scatter(0, 0, marker='o', color='gray')
ax.scatter(np.real(z), np.imag(z), marker='s', label="$z$")
ax.scatter(np.real(np.conjugate(z)), np.imag(np.conjugate(z)), marker='*', label="$z^*$")

# fix the axis limit
ax.set_xlim([-4, 4])
ax.set_ylim([-4, 4])

# show the grid lines 
ax.grid()

# show the labels 
ax.legend()

# show the plot 
plt.show()

# multiplication 
print(np.sqrt(np.conjugate(z)*z))

# norm / absolute value 
print(np.sqrt(2.0*2.0 + 3*3))
print(np.absolute(z))

# in radians 
print(np.angle(z)) 
# in angles 
print(np.angle(z, deg=True))

c = -1
z = 0 

# define an array 
max_iteration = 1000
threshold = 10
A = np.zeros(max_iteration, dtype=np.complex128)

r = np.linspace(-2, 2, 201)
i = np.linspace(-2, 2, 201)

def convergence(z):
    for index in range(max_iteration):
        f = z**2 + c
        # A[index] = f
        z = f 
        if np.absolute(z) > threshold:
            return False
    return True     


convergence_array = np.zeros((201, 201))
for index_real in range(101):
    for index_imag in range(101):
        z = r[index_real] + 1j*i[index_imag]
        if convergence(z):
            convergence_array[index_real, index_imag] = np.abs(z)
        

# make figure
fig = plt.figure()

# get the axes
ax = plt.axes()

# ax.scatter(np.real(A), np.imag(A))
ax.imshow(convergence_array)

plt.show()

