@@ -1777,27 +1777,165 @@ def chebroots(c):
1777
1777
return r
1778
1778
1779
1779
1780
- def chebinterpolate (func , deg , args = ()):
1780
+ def __dct (x , n = None ):
1781
+ """
1782
+ Discrete Cosine Transform type II
1783
+ N-1
1784
+ y[k] = 2 * sum x[n]*cos(pi*k*(2n+1)/(2*N)), 0 <= k < N.
1785
+ n=0
1786
+ Examples
1787
+ --------
1788
+ >>> x = np.arange(5)
1789
+ >>> x1 = np.arange(6)
1790
+ >>> y = x + 1j*x
1791
+ >>> y1 = x1 + 1j*x1
1792
+
1793
+ >>> np.allclose(__dct(x), [20. , -9.95959314, 0. , -0.89805595, 0. ])
1794
+ True
1795
+
1796
+ >>> np.allclose(__dct(x1),
1797
+ ... [30. , -14.41953704, 0. , -1.41421356, 0. , -0.27740142])
1798
+ True
1799
+
1800
+ >>> np.allclose(__dct(y), [20. +20.j, -9.95959314 -9.95959314j,
1801
+ ... 0. +0.j, -0.89805595 -0.89805595j,
1802
+ ... 0. +0.j ])
1803
+ True
1804
+
1805
+ >>> np.allclose(__dct(y1), [ 30. +30.j , -14.41953704-14.41953704j,
1806
+ ... 0. +0.j , -1.41421356 -1.41421356j,
1807
+ ... 0. +0.j , -0.27740142 -0.27740142j])
1808
+ True
1809
+
1810
+ >>> np.allclose(x, __idct(__dct(x)))
1811
+ True
1812
+
1813
+ >>> np.allclose(x, __dct(__idct(x)))
1814
+ True
1815
+
1816
+ References
1817
+ ----------
1818
+ .. [1] 'A Fast Cosine Transform in One and Two Dimensions', by J.
1819
+ Makhoul, `IEEE Transactions on acoustics, speech and signal
1820
+ processing` vol. 28(1), pp. 27-34,
1821
+ :doi:`10.1109/TASSP.1980.1163351` (1980).
1822
+ .. [2] Wikipedia, "Discrete cosine transform",
1823
+ https://en.wikipedia.org/wiki/Discrete_cosine_transform
1824
+ """
1825
+ fft = np .fft .fft
1826
+ x = np .atleast_1d (x )
1827
+
1828
+ if n is None :
1829
+ n = x .shape [- 1 ]
1830
+
1831
+ if x .shape [- 1 ] < n :
1832
+ n_shape = x .shape [:- 1 ] + (n - x .shape [- 1 ],)
1833
+ xx = np .hstack ((x , np .zeros (n_shape )))
1834
+ else :
1835
+ xx = x [..., :n ]
1836
+
1837
+ real_x = np .all (np .isreal (xx ))
1838
+ if (real_x and (np .remainder (n , 2 ) == 0 )):
1839
+ xp = 2 * fft (np .hstack ((xx [..., ::2 ], xx [..., ::- 2 ])))
1840
+ else :
1841
+ xp = fft (np .hstack ((xx , xx [..., ::- 1 ])))[..., :n ]
1842
+
1843
+ w = np .exp (- 1j * np .arange (n ) * np .pi / (2 * n ))
1844
+
1845
+ y = xp * w
1846
+
1847
+ if real_x :
1848
+ return y .real
1849
+ return y
1850
+
1851
+
1852
+ def __idct (x , n = None ):
1853
+ """
1854
+ Inverse Discrete Cosine Transform type II
1855
+ N-1
1856
+ y[k] = 1/N sum w[n]*x[n]*cos(pi*k*(2n+1)/(2*N)), 0 <= k < N.
1857
+ n=0
1858
+ w[0] = 1/2
1859
+ w[n] = 1 for n>0
1860
+
1861
+ Examples
1862
+ --------
1863
+ >>> x = np.arange(5)
1864
+ >>> np.allclose(x, __idct(__dct(x)))
1865
+ True
1866
+
1867
+ >>> np.allclose(x, __dct(__idct(x)))
1868
+ True
1869
+
1870
+ References
1871
+ ----------
1872
+ .. [1] 'A Fast Cosine Transform in One and Two Dimensions', by J.
1873
+ Makhoul, `IEEE Transactions on acoustics, speech and signal
1874
+ processing` vol. 28(1), pp. 27-34,
1875
+ :doi:`10.1109/TASSP.1980.1163351` (1980).
1876
+ .. [2] Wikipedia, "Discrete cosine transform",
1877
+ https://en.wikipedia.org/wiki/Discrete_cosine_transform
1878
+ """
1879
+
1880
+ ifft = np .fft .ifft
1881
+ x = np .atleast_1d (x )
1882
+
1883
+ if n is None :
1884
+ n = x .shape [- 1 ]
1885
+
1886
+ w = np .exp (1j * np .arange (n ) * np .pi / (2 * n ))
1887
+
1888
+ if x .shape [- 1 ] < n :
1889
+ n_shape = x .shape [:- 1 ] + (n - x .shape [- 1 ],)
1890
+ xx = np .hstack ((x , np .zeros (n_shape ))) * w
1891
+ else :
1892
+ xx = x [..., :n ] * w
1893
+
1894
+ real_x = np .all (np .isreal (x ))
1895
+ if (real_x and (np .remainder (n , 2 ) == 0 )):
1896
+ xx [..., 0 ] = xx [..., 0 ] * 0.5
1897
+ yp = ifft (xx )
1898
+ y = np .zeros (xx .shape , dtype = complex )
1899
+ y [..., ::2 ] = yp [..., :n // 2 ]
1900
+ y [..., ::- 2 ] = yp [..., n // 2 ::]
1901
+ else :
1902
+ yp = ifft (np .hstack ((xx ,
1903
+ np .zeros_like (xx [..., 0 ]),
1904
+ np .conj (xx [..., :0 :- 1 ]))))
1905
+ y = yp [..., :n ]
1906
+
1907
+ if real_x :
1908
+ return y .real
1909
+ return y
1910
+
1911
+
1912
+ def chebinterpolate (func , deg , args = (), domain = None ):
1781
1913
"""Interpolate a function at the Chebyshev points of the first kind.
1782
1914
1783
- Returns the Chebyshev series that interpolates `func` at the Chebyshev
1784
- points of the first kind in the interval [-1, 1]. The interpolating
1785
- series tends to a minmax approximation to `func` with increasing `deg`
1786
- if the function is continuous in the interval.
1915
+ Returns the Chebyshev series that interpolates the multi-dimensional
1916
+ function `func` at the Chebyshev points of the first kind scaled and
1917
+ shifted to the `domain`. The interpolating series tends to a minmax
1918
+ approximation of `func` with increasing `deg` if the function is
1919
+ continuous in the input domain.
1787
1920
1788
1921
.. versionadded:: 1.14.0
1789
1922
1790
1923
Parameters
1791
1924
----------
1792
1925
func : function
1793
- The function to be approximated. It must be a function of a single
1794
- variable of the form ``f(x, a, b, c...)``, where ``a, b, c...`` are
1795
- extra arguments passed in the `args` parameter.
1796
- deg : int
1797
- Degree of the interpolating polynomial
1926
+ The function to be approximated. It must be a function of the form
1927
+ ``f(x1, x2,..., xn, a, b, c...)``, where ``x1, x2,..., xn`` are the
1928
+ n-dimensional coordinates and ``a, b, c...`` are extra arguments
1929
+ passed in the `args` parameter.
1930
+ deg : list of int, size ndim
1931
+ Degree of the interpolating polynomial used for each dimension.
1798
1932
args : tuple, optional
1799
1933
Extra arguments to be used in the function call. Default is no extra
1800
1934
arguments.
1935
+ domain : array-like, shape ndim x 2, optional
1936
+ defines the domain ``[a1, b1] x [a2, b2] x ... x [an, bn]`` over
1937
+ which `func` is interpolated. The default is None, in which case
1938
+ the domain is [-1,1] * len(deg))
1801
1939
1802
1940
Returns
1803
1941
-------
@@ -1808,10 +1946,17 @@ def chebinterpolate(func, deg, args=()):
1808
1946
Examples
1809
1947
--------
1810
1948
>>> import numpy.polynomial.chebyshev as C
1811
- >>> C.chebfromfunction(lambda x: np.tanh(x) + 0.5, 8)
1812
- array([ 5.00000000e-01, 8.11675684e-01, -9.86864911e-17,
1813
- -5.42457905e-02, -2.71387850e-16, 4.51658839e-03,
1814
- 2.46716228e-17, -3.79694221e-04, -3.26899002e-16])
1949
+ >>> c1 = C.chebinterpolate(lambda x: np.tanh(x) + 0.5, 8)
1950
+ >>> x = C.chebpts1(9)
1951
+ >>> np.all(np.abs(C.chebval(x, c1) - np.tanh(x)-0.5) < 1e-15)
1952
+ True
1953
+
1954
+ Two-dimensional interpolation to machine accuracy
1955
+ >>> x1,x2 = np.meshgrid(x,x)
1956
+ >>> c2 = C.chebinterpolate(lambda x,y: np.tanh(x+y) + 0.5, deg=(8, 8))
1957
+ >>> np.all(np.abs(C.chebval2d(x1, x2, c2) - np.tanh(x1+x2)-0.5) < 1e-15)
1958
+ True
1959
+
1815
1960
1816
1961
Notes
1817
1962
-----
@@ -1824,24 +1969,41 @@ def chebinterpolate(func, deg, args=()):
1824
1969
zero. For instance, if the function is even then the coefficients of the
1825
1970
terms of odd degree in the result can be set to zero.
1826
1971
1972
+ References
1973
+ ----------
1974
+ .. [1] 'A Survey of Methods of Computing Minimax and Near-Minimax
1975
+ Polynomial Approximations for Functions of a Single Independent
1976
+ Variable' by W. Fraser, `Journal of the ACM` (JACM),
1977
+ vol. 12(3), pp. 295-314, (1965)
1978
+ .. [2] MathWorld, 'Chebyshev Approximation Formula',
1979
+ https://mathworld.wolfram.com/ChebyshevApproximationFormula.html
1980
+ .. [3] Wikipedia, 'Chebyshev nodes',
1981
+ http://en.wikipedia.org/wiki/Chebyshev_nodes
1982
+
1827
1983
"""
1828
- deg = np .asarray (deg )
1984
+ deg = np .atleast_1d (deg )
1829
1985
1830
1986
# check arguments.
1831
- if deg .ndim > 0 or deg .dtype .kind not in 'iu' or deg .size == 0 :
1987
+ if deg .ndim != 1 or deg .dtype .kind not in 'iu' or deg .size == 0 :
1832
1988
raise TypeError ("deg must be an int" )
1833
- if deg < 0 :
1989
+ if np . any ( deg < 0 ) :
1834
1990
raise ValueError ("expected deg >= 0" )
1835
-
1836
1991
order = deg + 1
1837
- xcheb = chebpts1 (order )
1838
- yfunc = func (xcheb , * args )
1839
- m = chebvander (xcheb , deg )
1840
- c = np .dot (m .T , yfunc )
1841
- c [0 ] /= order
1842
- c [1 :] /= 0.5 * order
1992
+ ndim = len (order )
1843
1993
1844
- return c
1994
+ if domain is None :
1995
+ domain = chebdomain .tolist () * ndim
1996
+ domain = np .atleast_2d (domain ).reshape ((- 1 , 2 ))
1997
+ x_i = [pu .mapdomain (chebpts1 (o ), chebdomain , d )
1998
+ for o , d in zip (order , domain )]
1999
+ c = func (* np .meshgrid (* x_i ), * args )
2000
+
2001
+ for i in range (ndim ):
2002
+ c = __dct (c [..., ::- 1 ])
2003
+ c [..., 0 ] /= 2.
2004
+ if i < ndim - 1 :
2005
+ c = np .moveaxis (c , source = - 1 , destination = 0 )
2006
+ return c / np .product (order )
1845
2007
1846
2008
1847
2009
def chebgauss (deg ):
@@ -2060,13 +2222,12 @@ def interpolate(cls, func, deg, domain=None, args=()):
2060
2222
2061
2223
Notes
2062
2224
-----
2063
- See `numpy.polynomial.chebfromfunction ` for more details.
2225
+ See `numpy.polynomial.chebyshev.chebinterpolate ` for more details.
2064
2226
2065
2227
"""
2066
2228
if domain is None :
2067
2229
domain = cls .domain
2068
- xfunc = lambda x : func (pu .mapdomain (x , cls .window , domain ), * args )
2069
- coef = chebinterpolate (xfunc , deg )
2230
+ coef = chebinterpolate (func , deg , args = args , domain = domain )
2070
2231
return cls (coef , domain = domain )
2071
2232
2072
2233
# Virtual properties
0 commit comments