The Chebfun minimax
code computes rational minimax approximations -- i.e., best approximations in the maximum norm -- for real functions on a real interval. For complex functions on a complex domain, the corresponding computation can now be done by aaa
, thanks to the recent introduction of a "AAA-Lawson iteration" [1].
For example, suppose we want to find the degree $n=4$ minimax approximation to $e^z$ on the unit circle (i.e., at most 4 zeros and 4 poles). We can do it like this:
tic Z = exp(2i*pi*(1:1000)/1000); F = exp(Z); r = aaa(F,Z,'degree',4);
If we plot the error curve, which is the image of the unit circle under $(f-r)(z)$, we see what looks like a perfect circle of radius 4e-8:
E = F - r(Z); plot(E), grid on error = norm(E,inf) ylim(5e-8*[-1 1]), axis equal title('degree 4 error curve on a disk')
error = 3.938867571915709e-08
In fact, it is not exactly a circle, but the radius (in theory) varies by only about one part in $10^{8}$. And its winding number is not 1 but $2n+1 = 9$:
a = unwrap(angle(E([1:end 1]))); winding_number = (a(end)-a(1))/(2*pi)
winding_number = 9
The observation that complex minimax approximants of smooth functions on smooth domains have nearly-circular error curves goes back to around 1980 and is the basis of the Carathéodory-Fejér method for computing such approximations [2], implemented (for a real interval) in Chebfun's cf
code. However, aaa
can also compute approximations that are not in this regime. For example, here is a set $Z$ defining a triangle inscribed in the unit circle:
omega = exp(2i*pi/3); Z = chebpts(1001,[1,omega]); Z = [Z; omega*Z; omega^2*Z];
If we approximate $e^z$ on this set, we get an error curve with three corners:
F = exp(Z); r = aaa(F,Z,'degree',4); E = F - r(Z); plot(E), grid on error = norm(E,inf) ylim(3.5e-9*[-1 1]), axis equal title('degree 4 error curve on a triangle')
error = 2.755289265190678e-09
Note that the error curve is close to a circle for most of the way around. Again the winding number is 9:
a = unwrap(angle(E([1:end 1]))); winding_number = (a(end)-a(1))/(2*pi)
winding_number = 9
We can do crazier things. For example, let's take Z to be 500 Chebyshev points in the unit interval together with a cloud of 1000 points above it and to the right:
Z = .5 + rand(2000,1) + .5i + 1i*rand(2000,1); Z = Z(abs(Z-(1+1i))<.5); Z = Z(1:1000); Z = [Z; chebpts(500)]; MS = 'markersize'; plot(Z,'.k',MS,4) ylim([-.5 2]), axis equal title('A crazy domain for approximation')
Now we approximate and plot the errors as dots. The red circle show that once again, the errors fit snugly in a disk.
F = exp(Z); r = aaa(F,Z,'degree',4); E = F - r(Z); error = norm(E,inf) plot(error*chebfun('exp(pi*1i*x)'),'r'), hold on plot(E,'.k',MS,6), grid on, hold off ylim(4e-8*[-1 1]), axis equal title('Error on the crazy domain')
error = 3.233716917409685e-08
Why isn't the fit snugger than this? As it happens, the Lawson iteration converges toward the optimum and by default, Chebfun takes just 20 steps, which for this problem isn't really enough. By instructing Chebfun to take more steps, we can get the minimax approximant to higher accuracy:
r = aaa(F,Z,'degree',4,'lawson',200); E = F - r(Z); error = norm(E,inf) plot(error*chebfun('exp(pi*1i*x)'),'r'), hold on plot(E,'.k',MS,6), grid on, hold off ylim(4e-8*[-1 1]), axis equal title('Same but more accurate')
error = 3.252078546778076e-08
The aaa
code isn't always successful at computing minimax approximations, but usually it works.
At present, aaa
just works for type $(m,n)$ rational approximation with $m=n$. So far as we know, this is the only code in existence for complex rational minimax approximation.
total_time_for_this_example = toc
total_time_for_this_example = 2.647419000000000
[1] Y. Nakatsukasa and L. N. Trefethen, An algorithm for real and complex rational minimax approximation, SIAM J. Sci. Comput., 42 (2020), A3157-A3179.
[2] L. N. Trefethen, Rational Chebsyhev approximation on the unit disk, Numer. Math. 37 (1981), 297--320.