-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpadeapprox.m
More file actions
147 lines (119 loc) · 4.12 KB
/
padeapprox.m
File metadata and controls
147 lines (119 loc) · 4.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
function [r, a, b, mu, nu, poles, residues] = padeapprox(f, m, n, tol)
%PADEAPPROX Pade approximation to a function or Taylor series.
% [R, A, B, MU, NU, POLES, RESIDUES] = PADEAPPROX(F, M, N, TOL) constructs a
% Pade approximant to F using the robust algorithm from [1] based on the SVD.
% F must be a function handle or a vector of coefficients f_0, ..., f_{m + n},
% and if F is a function handle, the function must be analytic in a
% neighborhood of the unit disc, since the coefficients are computed via FFT.
% M and N are the desired numerator and denominator degrees, respectively, and
% must be nonnegative. The optional TOL argument specifies the relative
% tolerance; if omitted, it defaults to 1e-14. Set TOL to 0 to turn off
% robustness. The output is a function handle R of for an exact type (MU, NU)
% Pade approximant to F with coefficient vectors A and B and, optionally, the
% POLES and RESIDUES.
%
% This code is included in the Chebfun distribution for the convenience of
% readers of _Approximation Theory and Approximation Practice_, but it is not
% actually a Chebfun code. A Chebfun analogue is CHEBPADE.
%
% References:
%
% [1] P. Gonnet, S. Guettel, and L. N. Trefethen, "ROBUST PADE APPROXIMATION
% VIA SVD", SIAM Rev., 55:101-117, 2013.
%
% See also CHEBPADE.
% Copyright 2014 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.
% Default to relative tolerance of 1e-14.
if ( nargin < 4 )
tol = 1e-14;
end
% Compute coefficients if necessary.
if ( ~isnumeric(f) )
% Sample at many roots of unity and use FFT to get coeffs.
N = 2048;
z = exp(2i*pi*(0:N-1)'/N);
f = fft(f(z))/N;
% Discard near-zero coefficients.
tc = 1e-15*norm(f);
f(abs(f) < tc) = 0;
% Remove imaginary rounding errors. (Make real functions real.)
if ( norm(imag(f), inf) < tc )
f = real(f);
end
end
% Make sure c is long enough but not longer than necessary.
c = [f(:) ; zeros(m + n + 1 - length(f), 1)];
c = c(1:m+n+1);
% Compute absolute tolerance.
ts = tol*norm(c);
% Compute the Pade approximation.
if ( norm(c(1:m+1), inf) <= tol*norm(c, inf) ) % Special case r = 0.
a = 0;
b = 1;
mu = -inf;
nu = 0;
else % General case.
% First row/column of Toeplitz matrix.
row = [c(1) zeros(1,n)];
col = c;
% Do diagonal hopping across block.
while ( true )
% Special case n == 0.
if (n == 0)
a = c(1:m+1);
b = 1;
break
end
% Form Toeplitz matrix.
Z = toeplitz(col(1:m+n+1), row(1:n+1));
% Compute numerical rank.
C = Z(m+2:m+n+1,:);
rho = sum(svd(C) > ts);
if ( rho == n)
break
end
% Decrease mn, n if rank-deficient.
m = m - (n - rho);
n = rho;
end
% Hopping finished. Now compute b and a.
if ( n > 0 )
[U, S, V] = svd(C,0);
% Null vector gives b.
b = V(:,n+1);
% Do final computation via reweighted QR for better zero preservation.
D = diag(abs(b) + sqrt(eps));
[Q, R] = qr((C*D).');
% Compensate for reweighting.
b = D*Q(:,n+1);
b = b/norm(b);
% Multiplying gives a.
a = Z(1:m+1,1:n+1)*b;
% Count leading zeros of b.
lam = find(abs(b) > tol, 1, 'first') - 1;
% Discard leading zeros of b and a.
b = b(lam+1:end);
a = a(lam+1:end);
% Discard trailing zeros of b.
b = b(1:find(abs(b) > tol, 1, 'last'));
end
% Discard trailing zero coefficients in a.
a = a(1:find(abs(a) > ts, 1, 'last'));
% Normalize.
a = a/b(1);
b = b/b(1);
% Exact numerator, denominator degrees.
mu = length(a) - 1;
nu = length(b) - 1;
end
% Function handle for r.
r = @(z) polyval(a(end:-1:1), z)./polyval(b(end:-1:1), z);
if ( nargout > 5 )
% Compute poles if requested.
poles = roots(b(end:-1:1));
% Estimate residues.
t = max(tol, 1e-7); % Perturbation for residue estimate.
residues = t*(r(poles + t) - r(poles - t))/2;
end
end