Skip to main content

Chapter 45 Complex Numbers and Analysis

Julia handles complex numbers in a natural manner. The type Complex is part of the Base package and is a subtype of the abstract data type Number. In this chapter, we go through basics of complex numbers in julia and see linear algebra and fourier transforms. You should have some basic knowledge of complex numbers before proceeding.

Section 45.1 Complex Numbers

Entering
z1 = 1+2im
and checking the type with typeof(z1) returns Complex{Int64} which indicates that it is parametric type where the individual elements are integers. Notice that im is the imaginary constant. Naturally, there is a lot of basic arithmetic operations available, so if
 z2 = 5-2im 
Then
Note the difference between the 3rd and 4th operation. The 3rd one does floating-point division, so the result is a Complex number of floats. The 4th does division resulting in Rational numbers. Test with typeof on both of these results.

Subsection 45.1.1 Functions of Complex Numbers

Most functions ``just work’’ in that they return the function evaluated at the complex number, however you need some basic understanding about what this means.
  • sqrt(z1) returns 1.272019649514069 + 0.7861513777574233im.
  • atan(z1) returns 1.3389725222944935 + 0.40235947810852507im.
  • log(-1+0im) returns 0.0 + 3.141592653589793im
  • exp(pi*im) returns -1.0 + 1.2246467991473532e-16im.
Although we won’t go into how these are calculated
 1 
A firm understanding of what the sine of a complex number requires some complex analysis
, note that you get answers. For log(-1+0im), this shows that if you are considering imaginary numbers, you can take the logarithm of a negative number, which is not allowed in the reals.
Also, the last one is the famous equation \(e^{i\pi}+1=0\) however since it using floating-point to do this, you get round-off error due to the limited precision.

Subsection 45.1.2 Functions with Special Meaning for Complex Numbers

There are some functions that have special means for complex numbers. The functions real and imag return the real and imaginary part of the number (the result of each is a Real, generally an Int, Float or Rational.
The absolute value of a complex number is defined as the distance in the complex plane from the origin or if \(z=a+bi\text{,}\) then
\begin{equation*} z = \sqrt{a^2+b^2} \end{equation*}
Also, the complex conjugate, generally denoted \(\bar{z}\text{,}\) is
\begin{equation*} \bar{z} = a-bi \end{equation*}
  • real(z1) returns 1.
  • imag(z1) returns 2.
  • abs(z1) returns 2.23606797749979
  • abs2(z1) returns 5, which is the square of the absolute value. This is generally used for speed in that a square root is not needed.
  • conj(z1) returns 1 - 2im.
  • angle(z1) returns 1.1071487177940904 is the argument of \(z\text{,}\) which is the angle in radians of the point plotted in the complex plane.

Section 45.2 Linear Algebra with Complex Numbers

There are many applications (including Fourier Transforms that we will see in the next section) involving matrices of complex numbers and the corresponding functions.
The functions discussed in Chapter 40 work with matrices involving complex numbers in a seamless manner including sums, differences, scalar and non-scalar multiplication and solving.
However there are many functions that have different meaning with complex numbers. Take for example, the matrix
 C = [1 -im;2+im 3]
and if we take the transpose using
 C' 
the result is
2×2 adjoint(::Matrix{Complex{Int64}}) with eltype Complex{Int64}:
  1+0im  2-1im
  0+1im  3+0im
Unless you know how the transpose works with complex matrices, this may be surprising in that as the two non-diagonal element actually both switch as well as have the conjugate applied.
Notice also that the type of the result gives a hint at what the ' operator actually does. Thus this is the adjoint of the matrix.

Section 45.3 Discrete Fourier Transforms

The Discrete Fourier Transform or DFT is a function that takes a vector in \(\mathbb{R}^n\) or (\(\mathbb{C}^n\)) to \(\mathbb{C}^n\text{.}\) In particular it is
\begin{equation} \hat{x}_k = \sum_{j=1}^N x_j e^{(-2\pi i kj)/N}\tag{45.1} \end{equation}
where \(\mathbf{x}\) is the input vector, \(i\) is the imaginary constant and \(N\) is the length of the vector.
The DFT has multiple applications including transforming a time-series to a set of frequencies (and this is often used in filter), solving partial differential equations and data compression. We will see some of these later.
From a mathematical point of view the DFT in (45.1) can be thought of as the matrix product:
\begin{equation*} \hat{\mathbf{x}} = F \mathbf{x} \end{equation*}
where
\begin{equation*} F = \begin{bmatrix} \omega^{0\cdot 0} \amp \omega^{0 \cdot 1} \amp \cdots \amp \omega^{0 \cdot (N-1)} \\ \omega^{1\cdot 0} \amp \omega^{1 \cdot 1} \amp \cdots \amp \omega^{1 \cdot (N-1)} \\ \vdots \amp \amp \amp \vdots \\ \omega^{(N-1)\cdot 0} \amp \omega^{(N-1)\cdot 1} \amp \cdots \amp \omega^{(N-1)(N-1)}\\ \end{bmatrix} \end{equation*}
where
\begin{equation*} \omega = e^{-2\pi i/N} \end{equation*}
is the primitive \(N\)th root of unity.
As an example, let x=[1,0,2,0] and then we will define
 F = [exp(j*k*2*pi*im/4) for j=0:3,k=0:3] 
which returns
4×4 Matrix{ComplexF64}:
  1.0+0.0im           1.0+0.0im          …           1.0+0.0im
  1.0+0.0im   6.12323e-17+1.0im             -1.83697e-16-1.0im
  1.0+0.0im          -1.0+1.22465e-16im             -1.0+3.67394e-16im
  1.0+0.0im  -1.83697e-16-1.0im              5.51091e-16+1.0im
And if we want the DFT of the vector x, then
 xt = F*x 
which returns
4-element Vector{ComplexF64}:
  3.0 + 0.0im
 -1.0 + 2.4492935982947064e-16im
  3.0 - 4.898587196589413e-16im
 -1.0 + 7.347880794884119e-16im
Note that this is virtually a real vector in that the imaginary parts are due to round off errors and near the precision of Float64 types.

Subsection 45.3.1 Fast Fourier Transform

You can probably tell from the matrix \(F\) above that there is a lot of symmetry to the matrix. Not only is it symmetric in the sense that \(F = F^{T}\text{,}\) but due the fact that exponentials with imaginary powers are actually periodic functions, there are additional
(Find a good reference for how the FFT works)
There are a number of packages that perform the fast fourier transform, however, the FFTW (which stands for the Fastest Fourier Transform in the West) claims to be the fastest. To use this, first add FFTW and
using FFTW
and then use the fft function.
 fft(x) 
which returns nearly nthe same as above or
4-element Vector{ComplexF64}:
  3.0 + 0.0im
 -1.0 + 0.0im
  3.0 + 0.0im
 -1.0 + 0.0im
where the difference is in round-off errors.