@@ -40,20 +40,85 @@ class Chebyshev(Filter):
40
40
41
41
"""
42
42
43
- def __init__ (self , G , filters , order = 30 ):
43
+ def __init__ (self , G , coefficients ):
44
44
45
45
self .G = G
46
- self .order = order
47
46
48
- try :
49
- self ._compute_coefficients (filters )
50
- self .Nf = filters .Nf
51
- except :
52
- self ._coefficients = np .asarray (filters )
53
- while self ._coefficients .ndim < 3 :
54
- self ._coefficients = np .expand_dims (self ._coefficients , - 1 )
55
- self .Nf = self ._coefficients .shape [1 ]
47
+ coefficients = np .asarray (coefficients )
48
+ while coefficients .ndim < 3 :
49
+ coefficients = np .expand_dims (coefficients , - 1 )
50
+
51
+ self .Nout , self .Nin = coefficients .shape [1 :]
52
+ self .Nf = self .Nout * self .Nin
53
+ self ._coefficients = coefficients
54
+
55
+ # That is a factory method.
56
+ @classmethod
57
+ def from_filter (cls , filters , order = 30 , n = None ):
58
+ r"""Compute the Chebyshev coefficients which approximate the filters.
59
+
60
+ The :math:`K+1` coefficients, where :math:`K` is the polynomial order,
61
+ to approximate the function :math:`f` are computed by the discrete
62
+ orthogonality condition as
63
+
64
+ .. math:: a_k \approx \frac{2-\delta_{0k}}{N}
65
+ \sum_{n=0}^{N-1} T_k(x_n) f(x_n),
66
+
67
+ where :math:`\delta_{ij}` is the Kronecker delta function and the
68
+ :math:`x_n` are the N shifted Gauss–Chebyshev zeros of :math:`T_N(x)`,
69
+ given by
70
+
71
+ .. math:: x_n = \frac{\lambda_\text{max}}{2}
72
+ \cos\left( \frac{\pi (2k+1)}{2N} \right)
73
+ + \frac{\lambda_\text{max}}{2}.
74
+
75
+ For any N, these approximate coefficients provide an exact
76
+ approximation to the function at :math:`x_k` with a controlled error
77
+ between those points. The exact coefficients are obtained with
78
+ :math:`N=\infty`, thus representing the function exactly at all points
79
+ in :math:`[0, \lambda_\text{max}]`. The rate of convergence depends on
80
+ the function and its smoothness.
81
+
82
+ Parameters
83
+ ----------
84
+ filters : filters.Filter
85
+ A filterbank (:class:`Filter`) to be approximated by a set of
86
+ Chebyshev polynomials.
87
+ order : int
88
+ The order of the Chebyshev polynomials.
89
+ n : int
90
+ The number of Gauss–Chebyshev zeros used to approximate the
91
+ coefficients. Defaults to the polynomial order plus one.
92
+
93
+ Examples
94
+ --------
95
+ >>> G = graphs.Ring(50)
96
+ >>> G.estimate_lmax()
97
+ >>> g = filters.Filter(G, lambda x: 2*x)
98
+ >>> h = filters.Chebyshev.from_filter(g, order=4)
99
+ >>> print(', '.join([str(int(c)) for c in h._coefficients]))
100
+ 4, 4, 0, 0, 0
101
+
102
+ """
103
+ lmax = filters .G .lmax
104
+
105
+ if n is None :
106
+ n = order + 1
107
+
108
+ points = np .pi * (np .arange (n ) + 0.5 ) / n
56
109
110
+ # The Gauss–Chebyshev zeros of Tk(x), scaled to [0, lmax].
111
+ zeros = lmax / 2 * np .cos (points ) + lmax / 2
112
+
113
+ # TODO: compute with scipy.fftpack.dct().
114
+ c = np .empty ((order + 1 , filters .Nf ))
115
+ for i , kernel in enumerate (filters ._kernels ):
116
+ for k in range (order + 1 ):
117
+ T_k = np .cos (k * points ) # Chebyshev polynomials of order k.
118
+ c [k , i ] = 2 / n * kernel (zeros ).dot (T_k )
119
+ c [0 , :] /= 2
120
+
121
+ return cls (filters .G , c )
57
122
58
123
@staticmethod
59
124
def scale_data (x , lmax ):
@@ -106,13 +171,6 @@ def _filter(self, s, method, _):
106
171
except AttributeError :
107
172
raise ValueError ('Unknown method {}.' .format (method ))
108
173
109
- def _compute_coefficients (self , filters ):
110
- r"""Compute the coefficients of the Chebyshev series approximating the filters.
111
-
112
- Some implementations define c_0 / 2.
113
- """
114
- pass
115
-
116
174
def _evaluate_direct (self , c , x ):
117
175
r"""Evaluate Fout*Fin polynomials at each value in x."""
118
176
K , F = c .shape [:2 ]
@@ -125,13 +183,13 @@ def _evaluate_direct(self, c, x):
125
183
def _evaluate_recursive (self , c , x ):
126
184
"""Evaluate a Chebyshev series for y. Optionally, times s.
127
185
128
- .. math: p(y ) = \sum_{k=0}^{K} a_k * T_k(y ) * s
186
+ .. math:: p(x ) = \sum_{k=0}^{K} a_k * T_k(x ) * s
129
187
130
188
Parameters
131
189
----------
132
190
c: array-like
133
191
set of Chebyshev coefficients. (size K x F where K is the polynomial order, F is the number of filters)
134
- y : array-like
192
+ x : array-like
135
193
vector to be evaluated. (size N x 1)
136
194
vector or matrix
137
195
signal: array-like
@@ -171,7 +229,7 @@ def mult(c, x):
171
229
def dot (L , x ):
172
230
"""One diffusion step by multiplication with the Laplacian."""
173
231
x .shape = (M * Fin , N )
174
- return L .__rmul__ (x ) # x @ L
232
+ return L .__rmatmul__ (x ) # x @ L
175
233
176
234
x0 = s .view ()
177
235
result = mult (c [0 ], x0 )
@@ -195,7 +253,7 @@ def mult(c, s):
195
253
def dot (L , x ):
196
254
"""One diffusion step by multiplication with the Laplacian."""
197
255
x .shape = (M * Fout , N )
198
- y = L .__rmul__ (x ) # x @ L
256
+ y = L .__rmatmul__ (x ) # x @ L
199
257
x .shape = (M , Fout , N )
200
258
y .shape = (M , Fout , N )
201
259
return y
0 commit comments