In this notebook, we review some properties of the complex exponential function. This function plays an important role for defining and understanding the Fourier transform, see Section 2.3.2 of [Müller, FMP, Springer 2015].
One encounters the real exponential function exp:R→R in the context of many mathematical applications, and the function can be characterized in many different ways. Historically, the exponential function was studied already by Johann Bernoulli in the 17th century when considering interest rates: Assume that an amount of 1 earns an interest a at an annual rate compounded monthly. Then the interest earned each month is a12 times the current value, so that each month the total value is multiplied by (1+a12) and the value at the end of the year is (1+a12)12. In case the interest is compounded every day, it becomes (1+a365)365. Letting the time intervals grow per year by making them shorter leads to the limit definition of the exponential function
exp(a)=limn→∞(1+an)n,which was first given by Leonhard Euler. The constant e:=exp(1)≈2.71828… is also known as Euler's number. By expanding the n-fold product in the above definition, one can show that the exponential function can also be expressed by the following power series:
exp(a):=∞∑n=0ann!=1+a+a21⋅2+a31⋅2⋅3+…with a∈R. Replacing in the power series the real-valued variable a∈R by a complex-valued variable c∈C, one still obtains the complex exponential function exp:C→C given by
exp(c):=∞∑n=0cnn!=1+c+c21⋅2+c31⋅2⋅3+…Based on the definition of the complex exponential function, one can also extend the definition of trigonometric functions (e.g. sin and cos) to complex arguments.
The following implementation yields an approximation of the power series by considering only the first N terms specified by the parameter N∈N. For the case c=1, this yields an approximation for the number e.
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
def exp_power_series(c, N):
"""Compute power series for exponential function
Notebook: C2_ExponentialFunction.ipynb
Args:
c: Complex number
N: Number of summands used for approximation
Returns:
exp_c: Approximation of exp(c)
"""
exp_c = 1
c_power = 1
nfac = 1
for n in range(1, N):
nfac *= n
c_power *= c
exp_c += c_power / nfac
return exp_c
c=1
print('Approximation (N = 1):', exp_power_series(c, 1))
print('Approximation (N = 2):', exp_power_series(c, 2))
print('Approximation (N = 4):', exp_power_series(c, 4))
print('Approximation (N = 8):', exp_power_series(c, 8))
print('Approximation (N = 12):', exp_power_series(c, 12))
print('Numpy: ', np.exp(c))
Based on the power series definition, one may prove two famous formulas of the exponential function that explain many of its properties. The first formula is knowns as exponentiation identity and says that
exp(c1+c2)=exp(c1)⋅exp(c2)for any complex numbers c1,c2∈C. In particular, this property explains the exponential increase for real arguments. For example,
exp(n)=exp(1+1+…+1)=exp(1)n=enfor n∈N. The second famous formula, which is known as Euler's formula, relates the values of the exponential function at purely imaginary arguments to trigonometric functions. It states that for the complex number c=iγ with some real-valued γ∈R one has the identity
exp(iγ)=cos(γ)+isin(γ).Actually, starting with the real sine and cosine functions, one often defines exp(iγ) by means of the Euler formula (rather than using the power series). This explains the periodic behavior of the real and imaginary part of exp along the imaginary (vertical) axis as shown in the next figure.
A, B = np.meshgrid(np.arange(-2, 2, 0.1), np.arange(-12, 12, 0.1))
C = A + B*1j
f_exp = np.exp(C)
plt.figure(figsize=(12, 4))
extent = [-2, 2, -12, 12]
plt.subplot(1, 3, 1)
plt.imshow(np.real(f_exp), aspect='auto', cmap='seismic', origin='lower', extent=extent)
plt.title('Real part Re(exp(c))')
plt.xlabel('a = Re(c)')
plt.ylabel('b = Im(c)')
plt.colorbar()
plt.subplot(1, 3, 2)
plt.imshow(np.imag(f_exp), aspect='auto', cmap='seismic', origin='lower', extent=extent)
plt.title('Imaginary part Im(exp(c))')
plt.xlabel('a = Re(c)')
plt.ylabel('b = Im(c)')
plt.colorbar()
plt.subplot(1, 3, 3)
plt.imshow(np.abs(f_exp), aspect='auto', cmap='gray_r', origin='lower', extent=extent)
plt.title('Absolute value |exp(c)|')
plt.xlabel('a = Re(c)')
plt.ylabel('b = Im(c)')
plt.colorbar()
plt.tight_layout()
The exponential function has a number of interesting properties:
exp(iγ)=exp(i(γ+2π))|exp(iγ)|=1¯exp(iγ)=exp(−iγ)exp(i(γ1+γ2))=exp(iγ1)exp(iγ2)dexp(iγ)dγ=iexp(iγ)In particular, note that the complex values exp(iγ) lie on the unit circle of the complex plane for all γ∈R. Furthermore, due to periodicity, it suffices to consider γ∈[0,2π). In fact, γ encodes the angle (in radians) of the complex number c=exp(iγ), while |c|=1. The following visualization shows how the values exp(iγ) change when increasing the angle γ from 0 to 2π:
from matplotlib import pyplot as plt
from matplotlib import ticker
%matplotlib inline
cmap = plt.cm.get_cmap('hsv') # hsv is nice because it is a circular color map
N = 64
fig = plt.figure(figsize=(5 * 3, 5))
ax1 = fig.add_subplot(1, 3, 1, projection='polar')
ax2 = fig.add_subplot(1, 3, 2)
ax3 = fig.add_subplot(1, 3, 3)
for i in range(N):
gamma = 2 * np.pi * i / N
c = np.exp(1j * gamma)
color = cmap(i / N)
ax1.plot([0, np.angle(c)], [0, np.abs(c)], color=color)
ax1.plot(np.angle(c), np.abs(c), 'o', color=color)
ax2.plot(gamma, np.real(c), 'o', color=color)
ax3.plot(gamma, np.imag(c), 'o', color=color)
ax2.grid()
ax2.set_xlabel('$\gamma$ [radians]')
ax2.set_ylabel('$\mathrm{Re}(\exp(i \gamma))$')
ax2.xaxis.set_major_formatter(ticker.FormatStrFormatter('$%s$'))
ax3.grid()
ax3.set_xlabel('$\gamma$ [radians]')
ax3.set_ylabel('$\mathrm{Im}(\exp(i \gamma))$')
ax3.xaxis.set_major_formatter(ticker.FormatStrFormatter('$%s$'))
plt.tight_layout()
Let N∈N>0 be a positive integer. A complex number ρ∈C is called an Nth root of unity if ρN=1. It is not hard to see that there are exactly N distinct Nth roots of unity. Additionally, if ρn≠1 for all n∈[1:N−1], it is called a primitive Nth root of unity.
With the properties mentioned above, it is easy to see that ρN:=exp(2πi/N) is such a primitive Nth root of unity. All Nth roots of unity can be generated by considering powers of ρN:
1=ρ0N,ρ1N,ρ2N,...,ρN−1NThe following plot shows all roots of unity for different integers N∈N>0. The primitive roots are indicated in red.
from math import gcd
import sys
sys.path.append('..')
import libfmp.c2
def plot_root_unity(N, figsize=(5, 5)):
root_unity = np.exp(2j * np.pi / N)
root_unity_power = 1
fig, ax = plt.subplots(figsize=figsize)
plt.grid()
plt.xlim([-1.4, 1.4])
plt.ylim([-1.4, 1.4])
plt.xlabel('$\mathrm{Re}$')
plt.ylabel('$\mathrm{Im}$')
plt.title('Roots of unity for $N=%d$'%N)
for n in range(0, N):
colorPlot = 'r' if gcd(n, N) == 1 else 'k'
libfmp.c2.plot_vector(root_unity_power, color=colorPlot)
plt.text(np.real(1.2*root_unity_power), np.imag(1.2*root_unity_power),
r'$\rho_{%s}^{%s}$' % (N, n), size='18',
color=colorPlot, ha='center', va='center')
root_unity_power *= root_unity
circle_unit = plt.Circle((0, 0), 1, color='lightgray', fill=0)
ax.add_artist(circle_unit)
plot_root_unity(N=8)
plot_root_unity(N=11)
plot_root_unity(N=12)