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.
Although we won’t go into how these are calculated, note that you get answers. For
1
A firm understanding of what the sine of a complex number requires some complex analysis
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*}
-
abs2(z1)returns5, which is the square of the absolute value. This is generally used for speed in that a square root is not needed. -
angle(z1)returns1.1071487177940904is 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.
\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.
