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