%% CHEBFUN GUIDE 5: COMPLEX CHEBFUNS
% Lloyd N. Trefethen, November 2009, revised February 2011
%% 5.1 Complex functions of a real variable
%%
% One of the attractive features of Matlab is that it handles
% complex arithmetic well.
% For example, here are 20 points on the upper half
% of the unit circle in the complex plane:
s = linspace(0,pi,20);
f = exp(1i*s);
plot(f,'.')
axis equal
%%
% In Matlab, both the variables i and j are initialized
% as i, the square root of -1, but this code uses
% 1i instead (just as one might write,
% for example, 3+2i or 2.2-1.1i). Writing the imaginary unit
% in this fashion is a common trick among Matlab programmers,
% for it avoids the risk of surprises caused by i or j having been
% overwritten by other values.
% The "axis equal" command ensures that the real and
% imaginary axes are scaled equally.
%%
% Here is a Chebfun analogue.
s = chebfun(@(s) s,[0 pi]);
f = exp(1i*s);
plot(f)
axis equal
%%
% The Chebfun semicircle is represented by a polynomial of low degree:
length(f)
plot(f,'.-')
axis equal
%%
% We can have fun with variations on the theme:
subplot(1,2,1), g = s.*exp(10i*s); plot(g), axis equal
subplot(1,2,2), h = exp(2i*s)+.3*exp(20i*s); plot(h), axis equal
%%
subplot(1,2,1), plot(g.^2), axis equal
subplot(1,2,2), plot(exp(h)), axis equal
%%
% Such plots make pretty pictures, but as always with Chebfun,
% the underlying operations involve precise mathematics
% carried out to many digits
% of accuracy. For example, the integral of g is -pi*i/10,
sum(g)
%%
% and the integral of h is zero:
sum(h)
%%
% Piecewise smooth complex chebfuns are also possible.
% For example, the following starts from a chebfun z defined
% as (1+0.5i)s for s on the interval [0,1] and
% 1+0.5i-2(s-1) for s on the interval [1,2].
z = chebfun('(1+.5i)*s','1+.5i-2*(s-1)',[0 1 2]);
subplot(1,2,1), plot(z), axis equal, grid on
subplot(1,2,2), plot(z.^2), axis equal, grid on
%%
% Actually, this way of constructing a piecewise chebfun is
% rather clumsy. An easier method is to use the "vertcat" feature
% of Chebfun, in which a construction like [f; g; h] constructs
% a single chebfun with the same values as f, g, and h, but on a
% domain concatenated together. Thus if the domains of f, g, h are
% [a,b], [c,d], and [e,d], then [f; g; h] has three pieces with domains
% [a,b], [b,b+(d-c)], [b+(d-c),b+(d-c)+(d-e)]. Using this trick,
% we can construct the chebfun z above in the following alternative manner:
s = chebfun(@(s) s,[0 1]);
zz = [(1+.5i)*s; 1+.5i-2*s];
norm(z-zz)
%% 5.2 Analytic functions and conformal maps
%
% A function is *analytic* if it is differentiable in the complex sense, or
% equivalently, if it has a convergent Taylor series near each point.
% Analytic functions do interesting things in the complex plane.
% In particular, away from points where the derivative is zero, they
% are *conformal maps*, which means that though they may scale and
% rotate an infinitesimal region, they preserve angles
% between intersecting curves.
%%
% For example, suppose we define R to be
% a chebfun corresponding to the four sides of a rectangle and
% we define X to be another chebfun corresponding to a cross inside R.
s = chebfun('s',[0 1]);
R = [1+s; 2+2i*s; 2+2i-s; 1+2i-2i*s];
LW = 'linewidth'; lw1 = 2; lw2 = 3;
clf, subplot(1,2,1), plot(R,LW,lw2), grid on, axis equal
X = [1.3+1.5i+.4*s; 1.5+1.3i+.4i*s];
hold on, plot(X,'r',LW,lw2)
%%
% Here we see what happens to R and X under the maps z^2 and exp(z):
clf
subplot(1,2,1), plot(R.^2,LW,lw1), grid on, axis equal
hold on, plot(X.^2,'r',LW,lw2)
subplot(1,2,2), plot(exp(R),LW,lw1), grid on, axis equal
hold on, plot(exp(X),'r',LW,lw2)
%%
% We can take the same idea further and construct a grid in the
% complex plane, each segment of which is a piece of a chebfun that
% happens to be linear. In this case we accumulate the various
% pieces as successive columns of a quasimatrix, i.e., a "matrix" whose
% columns are chebfuns.
x = chebfun(@(x) x);
S = chebfun; % make an empty chebfun
for d = -1:.2:1
S = [S d+1i*x 1i*d+x]; % add 2 more lines to the collection
end
clf, subplot(1,2,1), plot(S), axis equal
%%
% Here are the exponential and tangent of the grid:
subplot(1,2,1), plot(exp(S)), axis equal
subplot(1,2,2), plot(tan(S)), axis equal
%%
% Here is a sequence that puts all three images together on
% a single scale:
clf
plot(S), hold on
plot(1.6+exp(S))
plot(6.6+tan(S))
axis equal, axis off
%%
% A particularly interesting set of conformal maps are the
% *Moebius transformations*, the rational functions of the form (az+b)/(cz+d)
% for constants a,b,c,d. For example, here is a square and its
% image under the map w = 1/(1+z), and the image of the image under the
% same map, and the image of the image of the image. We also plot
% the limit point given by the equation z = 1/(1+z), i.e., z = (sqrt(5)-1)/2.
moebius = @(z) 1./(1+z);
s = chebfun(@(s) s,[0 1]);
S = [-.5i+s; 1-.5i+1i*s; 1+.5i-s; .5i-1i*s];
clf
for j = 1:3
S = [S moebius(S(:,j))];
end
plot(S)
hold on, axis equal
plot((sqrt(5)-1)/2,0,'.k','markersize',4)
%%
% Here's a prettier version of the same image using the
% Chebfun "fill" command.
S = [-.5i+s; 1-.5i+1i*s; 1+.5i-s; .5i-1i*s];
clf
fill(real(S),imag(S),[.5 .5 1]), axis equal, hold on
S = moebius(S); fill(real(S),imag(S),[.5 1 .5])
S = moebius(S); fill(real(S),imag(S),[1 .5 .5])
S = moebius(S); fill(real(S),imag(S),[.5 1 1 ])
plot((sqrt(5)-1)/2,0,'.k','markersize',4)
axis off
%% 5.3 Contour integrals
% If s is a real parameter and z(s) is a complex function of s,
% then we can define a contour integral in the complex plane like this:
%
% INT f(z(s)) z'(s) ds
%
% The contour in question is the curve described by z(s) as s varies
% over its range.
%%
% For example, in the example at the end of Section 5.1
% the contour consists of two straight segments
% that begin at 0 and end at -1+.5i. We can compute the integral of
% exp(-z^2) over the contour like this:
f = exp(-z.^2);
I = sum(f.*diff(z))
%%
% Notice how easily the contour integral is realized in
% Chebfun, even over a contour consisting of several pieces.
% This particular integral is related to the complex error function [Weideman 1994].
%%
% According to *Cauchy's theorem*, the integral of an analytic function
% around a closed curve is zero, or equivalently, the integral between two
% points z1 and z2 is path-independent. To verify this, we can
% compute the same integral over the straight segment going directly from
% 0 to -1+0.5i:
w = chebfun('(-1+.5i)*s',[0 1]);
f = exp(-w.^2);
I2 = sum(f.*diff(w))
%%
% A *meromorphic function* is a function that is analytic in a region of interest
% in the complex plane apart from possible poles.
% According to the *Cauchy integral formula*, (1/2i*pi) times the integral of
% a meromorphic function f around a closed contour is equal to the sum of the residues
% of f associated with any poles it may have in the enclosed region. The
% *residue* of f at a point z0 is the coefficient of the degree -1 term in
% its Laurent expansion at z0. For example, the function exp(z)/z^3
% has Laurent series z^(-3) + z^(-2) + (1/2)z^(-1) + (1/6)z^0 + ...
% at the origin, and so its residue there is 1/2. We can confirm this
% by computing the contour integral around a circle:
z = chebfun('exp(1i*s)',[0 2*pi]);
f = exp(z)./z.^3;
I = sum(f.*diff(z))/(2i*pi)
%%
% Notice that we have just computed the degree 2 Taylor coefficient of exp(z).
%%
% When Chebfun integrates around a circular contour
% like this, it does not take advantange of the fact that the integrand is
% periodic. That would be Fourier analysis as opposed to Chebyshev
% analysis, and a "Fourfun" system would be more efficient for such
% problems [Davis 1959]. Chebyshev analysis is more flexible, however, since it does
% not require periodicity, and the loss in efficiency is only about
% a factor of pi/2 [Hale & Trefethen 2008].
%%
% The contour does not have to have radius 1, or be centered at the origin:
z = chebfun('1+2*exp(1i*s)',[0 2*pi]);
f = exp(z)./z.^3;
I2 = sum(f.*diff(z))/(2i*pi)
%%
% Nor does the contour have to be smooth.
% Here let us compute the same result by integration over a square:
s = chebfun('s',[-1 1]);
z = [1+1i*s; 1i-s; -1-1i*s; -1i+s];
f = exp(z)./z.^3;
I3 = sum(f.*diff(z))/(2i*pi)
%%
% In Chebfun one
% can also construct more interesting contours of the kind that
% appear in complex variables texts. Here is an example:
c = [-2+.05i -.2+.05i -.2-.05i -2-.05i]; % 4 corners
s = chebfun('s',[0 1]);
z = [c(1)+s*(c(2)-c(1))
c(2)*c(3).^s./c(2).^s
c(3)+s*(c(4)-c(3))
c(4)*c(1).^s./c(4).^s];
clf, plot(z), axis equal, axis off
%%
% The integral of f(z) = log(z)tanh(z) around this contour will
% be equal to 2i*pi times the sum of the residues at the poles
% of f at +-0.5i*pi.
f = log(z).*tanh(z);
I = sum(f.*diff(z))
Iexact = 4i*pi*log(pi/2)
%% 5.4 Cauchy integrals and locating zeros and poles
%
% Here are some further examples of computations with
% Cauchy integrals. The Bernoulli number B_k is
% k! times the kth Taylor coefficient of z/((exp(z)-1).
% Here is B_10 compared with its exact value 5/66.
k = 10;
z = chebfun('5*exp(1i*s)',[0 2*pi]);
f = z./((exp(z)-1));
B10 = factorial(k)*sum((f./z.^(k+1)).*diff(z))/(2i*pi)
exact = 5/66
%%
% Notice that we have taken z to be a circle of radius 5.
% If the radius is 1, the accuracy is a good deal lower:
z = chebfun('exp(1i*s)',[0 2*pi]);
f = z./((exp(z)-1));
B10 = factorial(k)*sum((f./z.^(k+1)).*diff(z))/(2i*pi)
%%
% This problem of numerical instability would arise no matter
% how one calculated the integral over the unit circle; it is not
% the fault of Chebfun. For a study of how to pick
% the optimal radius, see [Bornemann 2009].
%%
% Another use of Cauchy integrals is to count zeros or
% poles of functions in specified regions. According to the
% *principle of the argument*, the number of zeros
% minus the number of poles of f in a region is
%
% N = (1/2i*pi) INT (f'/f) dz
%
% where the integral is taken over the boundary. Since f' = df/dz
% = (df/ds)(ds/dz), we can rewrite this as
%
% N = (1/2i*pi) INT (df/ds)/f ds.
%
% (What is really going on here is a calculation of the change of the
% argument of f as the boundary is traversed. In principle it
% should be possible to calculate this by the Matlab commands "angle" and "unwrap",
% but these have not yet been overloaded for chebfuns.)
% For example, the function f(z) = sin(z)^3 + cos(z)^3 clearly has no poles;
% how many zeros does it have in the disk about 0 of radius 2?
% The following calculation shows that the answer is 3:
z = chebfun('2*exp(1i*s)',[0 2*pi]);
f = sin(z).^3 + cos(z).^3;
N = sum((diff(f)./f))/(2i*pi)
%%
% Variations on this idea enable one to locate zeros and poles as well as
% count them. For example, we can locate a single zero with the formula
%
% r = (1/2i*pi) INT z (df/ds)/f ds
%
% [McCune 1966]. Here is the zero of the function above in the unit disk:
z = chebfun('exp(1i*s)',[0 2*pi]);
f = sin(z).^3 + cos(z).^3;
r = sum(z.*(diff(f)./f))/(2i*pi)
%%
% We can check the result by a more ordinary Chebfun calculation:
x = chebfun('x');
f = sin(x).^3 + cos(x).^3;
r = roots(f)
%%
% To find multiple zeros via Cauchy integrals, see [Delves & Lyness 1967].
%% 5.5 Alphabet soup
%
% The Chebfun command "scribble" returns a piecewise linear complex chebfun
% corresponding to a word spelled out in capital letters. For example:
f = scribble('Oxford University');
LW = 'linewidth'; lw = 2;
plot(f,LW,lw), xlim(1.1*[-1 1]), axis equal
%%
% This chebfun happens to have 67 pieces:
domain(f)
%%
% Though its applications are unlikely to be mathematical,
% f is a precisely defined mathematical object just like any other
% chebfun. If we wish, we can compute with it:
f(0), norm(f)
%%
% Perhaps more interesting is that we can apply functions to it
% and learn something in the process:
plot(exp(3i*f),'m',LW,lw), ylim(1.2*[-1 1]), axis equal
%%
% Does putting a box around enhance the image?
% (We do this by adding a second column of a Chebfun
% quasimatrix -- see Chapter 6.)
L = f.ends(end);
s = chebfun(@(x) x,[0 1]);
box0 = [-1.1-.05i+2.2*s;1.1-.05i+.22i*s;1.1+.17i-2.2*s;-1.1+.17i-.22i*s];
box = chebfun;
box{-1,1} = box0;
f = [f box];
plot(f,LW,lw), xlim(1.2*[-1 1]), axis equal
%%
clf, plot(exp((1+.2i)*f),LW,lw), axis equal, axis off
%%
plot(tan(f),LW,lw), axis equal, axis off
%%
% Next May 16, you might wish to write a greeting card for
% Pafnuty Lvovich Chebyshev, accurate as always to 15 digits:
f = scribble('Happy Birthday Pafnuty!');
L = f.ends(end);
g = @(z) exp(-2.2i+(2.5i+.4)*z);
clf, plot(g(f),'r',LW,lw), axis equal, axis off
circle = 1.12*chebfun(@(x) exp(2i*pi*x/L),[0 L]);
ellipse = 1.2*(circle + 1./circle)/2 + 1i*mean(imag(f));
hold on, plot(g(ellipse),'b',LW,lw)
%%
% You can find an example "Birthday cards and analytic function"
% in the Complex Variables section of the
% Chebfun Examples collection, and further related explorations in
% the Geometry section.
%% 5.6 References
%
% [Bornemann 2009] F. Bornemann, "Accuracy and stability of computing
% high-order derivatives of analytic functions by Cauchy integrals",
% Foundations of Computational Mathematics 11 (2011), 1-63.
%
% [Davis 1959] P. J. Davis, "On the numerical integration of periodic analytic
% functions", in R. E. Langer, ed., On Numerical Integration,
% Math. Res. Ctr., U. of Wisconsin, 1959, pp. 45-59.
%
% [Delves & Lyness 1967] L. M. Delves and J. N. Lyness, "A numerical
% method for locating the zeros of an analytic function", Mathematics
% of Computation 21 (1967), 543-560.
%
% [Hale & Trefethen 2008] N. Hale and L. N. Trefethen,
% "New quadrature formulas from conformal maps", SIAM Journal
% on Numerical Analysis 46 (2008), 930-948.
%
% [McCune 1966] J. E. McCune, "Exact inversion of dispersion relations",
% Physics of Fluids 9 (1966), 2082-2084.
%
% [Weideman 1994] J. A. C. Weideman, "Computation of the complex error
% function", SIAM Journal on Numerical Analysis 31 (1994), 1497-1518.