|
|
|
@ -17,14 +17,16 @@
|
|
|
|
|
# Licence: LGPL
|
|
|
|
|
# -------------------------------------------------------------------------
|
|
|
|
|
# !/usr/bin/env python
|
|
|
|
|
|
|
|
|
|
import warnings
|
|
|
|
|
from numpy.polynomial import polyutils as pu
|
|
|
|
|
from plotbackend import plotbackend as plt
|
|
|
|
|
import numpy as np
|
|
|
|
|
from numpy.fft import fft, ifft
|
|
|
|
|
from numpy import (zeros, ones, zeros_like, array, asarray, newaxis, arange,
|
|
|
|
|
logical_or, any, pi, cos, round, diff, all, exp, atleast_1d,
|
|
|
|
|
where, extract, linalg, sign, concatenate, floor, isreal,
|
|
|
|
|
conj, remainder, linspace, sum)
|
|
|
|
|
conj, remainder, linspace, sum, meshgrid, hstack)
|
|
|
|
|
|
|
|
|
|
from scipy.fftpack import dct, idct as _idct
|
|
|
|
|
from numpy.lib.polynomial import * # @UnusedWildImport
|
|
|
|
|
from scipy.misc.common import pade # @UnresolvedImport
|
|
|
|
|
__all__ = np.lib.polynomial.__all__
|
|
|
|
@ -1171,64 +1173,101 @@ def chebfit(fun, n=10, a=-1, b=1, trace=False):
|
|
|
|
|
f = fun
|
|
|
|
|
n = len(f)
|
|
|
|
|
# N-1
|
|
|
|
|
# c(k) = (2/N) sum w(n) f(n)*cos(pi*k*(2n+1)/(2N)), 0 <= k < N.
|
|
|
|
|
# c[k] = (2/N) sum w[n] f[n]*cos(pi*k*(2n+1)/(2N)), 0 <= k < N.
|
|
|
|
|
# n=0
|
|
|
|
|
#
|
|
|
|
|
# w(0) = 0.5, w(n)=1 for n>0
|
|
|
|
|
# w[0] = 0.5, w[n]=1 for n>0
|
|
|
|
|
|
|
|
|
|
ck = dct(f[::-1]) / n
|
|
|
|
|
ck[0] = ck[0] / 2.
|
|
|
|
|
return ck[::-1]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def dct(x, n=None):
|
|
|
|
|
def chebfit_dct(f, n=(10, ), domain=None):
|
|
|
|
|
"""
|
|
|
|
|
Discrete Cosine Transform
|
|
|
|
|
Fit Chebyshev series to N-dimensional function
|
|
|
|
|
so that f(x1, x2,..., xn) can be approximated by:
|
|
|
|
|
|
|
|
|
|
N-1
|
|
|
|
|
y[k] = 2* sum x[n]*cos(pi*k*(2n+1)/(2*N)), 0 <= k < N.
|
|
|
|
|
n=0
|
|
|
|
|
.. math:: f(x_1, x_2,...,x_n) = \\sum_{i,j,...k} c_i T_i(x_1)*...*c_k T_k(x_n) ,
|
|
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
>>> import numpy as np
|
|
|
|
|
>>> x = np.arange(5)
|
|
|
|
|
>>> np.abs(x-idct(dct(x)))<1e-14
|
|
|
|
|
array([ True, True, True, True, True], dtype=bool)
|
|
|
|
|
>>> np.abs(x-dct(idct(x)))<1e-14
|
|
|
|
|
array([ True, True, True, True, True], dtype=bool)
|
|
|
|
|
where Tk is the k'th Chebyshev polynomial of the first kind.
|
|
|
|
|
|
|
|
|
|
Reference
|
|
|
|
|
---------
|
|
|
|
|
http://en.wikipedia.org/wiki/Discrete_cosine_transform
|
|
|
|
|
http://users.ece.utexas.edu/~bevans/courses/ee381k/lectures/
|
|
|
|
|
"""
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
f : callable
|
|
|
|
|
function to approximate
|
|
|
|
|
n : list of integers, optional
|
|
|
|
|
number of base points (abscissas) used for each dimension.
|
|
|
|
|
Default n=10 (maximum 50)
|
|
|
|
|
domain : vector [a1,b1,a2,b2 ,..., an, bn], optional
|
|
|
|
|
defining the rectangle [a1, b1] x [a2, b2] x ...x [an, bn].
|
|
|
|
|
(default domain = (-1,1) * len(n))
|
|
|
|
|
|
|
|
|
|
x = atleast_1d(x)
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
ck : ndarray
|
|
|
|
|
polynomial coefficients in Chebychev form.
|
|
|
|
|
|
|
|
|
|
if n is None:
|
|
|
|
|
n = x.shape[-1]
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
Fit exponential function
|
|
|
|
|
|
|
|
|
|
if x.shape[-1] < n:
|
|
|
|
|
n_shape = x.shape[:-1] + (n - x.shape[-1],)
|
|
|
|
|
xx = hstack((x, zeros(n_shape)))
|
|
|
|
|
else:
|
|
|
|
|
xx = x[..., :n]
|
|
|
|
|
>>> import matplotlib.pyplot as plt
|
|
|
|
|
>>> domain = (0, 2)
|
|
|
|
|
>>> ck = chebfit_dct(np.exp, 7, domain)
|
|
|
|
|
>>> np.allclose(ck, [3.44152387e+00, 3.07252345e+00, 7.38000848e-01,
|
|
|
|
|
... 1.20520053e-01, 1.48805268e-02, 1.47579673e-03,
|
|
|
|
|
... 1.21719524e-04])
|
|
|
|
|
True
|
|
|
|
|
>>> x1 = map_to_interval(chebroot(9), *domain)
|
|
|
|
|
>>> ck1 = chebfit(np.exp(x1))
|
|
|
|
|
>>> np.allclose(ck1, [5.40019009e-07, 8.69418381e-06, 1.22261037e-04,
|
|
|
|
|
... 1.47582673e-03, 1.48805283e-02, 1.20520053e-01,
|
|
|
|
|
... 7.38000848e-01, 3.07252345e+00, 3.44152387e+00])
|
|
|
|
|
True
|
|
|
|
|
|
|
|
|
|
real_x = all(isreal(xx))
|
|
|
|
|
if (real_x and (remainder(n, 2) == 0)):
|
|
|
|
|
xp = 2 * fft(hstack((xx[..., ::2], xx[..., ::-2])))
|
|
|
|
|
else:
|
|
|
|
|
xp = fft(hstack((xx, xx[..., ::-1])))
|
|
|
|
|
xp = xp[..., :n]
|
|
|
|
|
x = np.linspace(0,4)
|
|
|
|
|
h = plt.plot(x, np.exp(x), 'r', x, chebvalnd(ck, x,ck,a,b), 'g.')
|
|
|
|
|
h = plt.plot(x, np.exp(x), 'r', x, chebvalnd(ck1, x,ck1,a,b),'b.')
|
|
|
|
|
plt.close()
|
|
|
|
|
|
|
|
|
|
See also
|
|
|
|
|
--------
|
|
|
|
|
chebval, chebvalnd
|
|
|
|
|
|
|
|
|
|
w = exp(-1j * arange(n) * pi / (2 * n))
|
|
|
|
|
Reference
|
|
|
|
|
---------
|
|
|
|
|
http://en.wikipedia.org/wiki/Chebyshev_nodes
|
|
|
|
|
http://mathworld.wolfram.com/ChebyshevApproximationFormula.html
|
|
|
|
|
|
|
|
|
|
y = xp * w
|
|
|
|
|
W. Fraser (1965)
|
|
|
|
|
"A Survey of Methods of Computing Minimax and Near-Minimax Polynomial
|
|
|
|
|
Approximations for Functions of a Single Independent Variable"
|
|
|
|
|
Journal of the ACM (JACM), Vol. 12 , Issue 3, pp 295 - 314
|
|
|
|
|
"""
|
|
|
|
|
n = np.atleast_1d(n)
|
|
|
|
|
if np.any(n > 50):
|
|
|
|
|
warnings.warn('CHEBFIT should only be used for n<50')
|
|
|
|
|
|
|
|
|
|
if real_x:
|
|
|
|
|
return y.real
|
|
|
|
|
if hasattr(f, '__call__'):
|
|
|
|
|
if domain is None:
|
|
|
|
|
domain = (-1,1) * len(n)
|
|
|
|
|
domain = np.atleast_2d(domain).reshape((-1, 2))
|
|
|
|
|
xi = [map_to_interval(chebroot(ni), d[0], d[1])
|
|
|
|
|
for ni, d in zip(n, domain)]
|
|
|
|
|
Xi = np.meshgrid(*xi)
|
|
|
|
|
ck = f(*Xi)
|
|
|
|
|
else:
|
|
|
|
|
return y
|
|
|
|
|
ck = f
|
|
|
|
|
n = ck.shape
|
|
|
|
|
|
|
|
|
|
ndim = len(n)
|
|
|
|
|
for i in range(ndim):
|
|
|
|
|
ck = dct(ck[...,::-1])
|
|
|
|
|
ck[..., 0] = ck[..., 0] / 2.
|
|
|
|
|
if i < ndim-1:
|
|
|
|
|
ck = np.rollaxis(ck, axis=-1)
|
|
|
|
|
return ck / np.product(n)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def idct(x, n=None):
|
|
|
|
@ -1256,35 +1295,7 @@ def idct(x, n=None):
|
|
|
|
|
http://en.wikipedia.org/wiki/Discrete_cosine_transform
|
|
|
|
|
http://users.ece.utexas.edu/~bevans/courses/ee381k/lectures/
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
x = atleast_1d(x)
|
|
|
|
|
|
|
|
|
|
if n is None:
|
|
|
|
|
n = x.shape[-1]
|
|
|
|
|
|
|
|
|
|
w = exp(1j * arange(n) * pi / (2 * n))
|
|
|
|
|
|
|
|
|
|
if x.shape[-1] < n:
|
|
|
|
|
n_shape = x.shape[:-1] + (n - x.shape[-1],)
|
|
|
|
|
xx = hstack((x, zeros(n_shape))) * w
|
|
|
|
|
else:
|
|
|
|
|
xx = x[..., :n] * w
|
|
|
|
|
|
|
|
|
|
real_x = all(isreal(x))
|
|
|
|
|
if (real_x and (remainder(n, 2) == 0)):
|
|
|
|
|
xx[..., 0] = xx[..., 0] * 0.5
|
|
|
|
|
yp = ifft(xx)
|
|
|
|
|
y = zeros(xx.shape, dtype=complex)
|
|
|
|
|
y[..., ::2] = yp[..., :n / 2]
|
|
|
|
|
y[..., ::-2] = yp[..., n / 2::]
|
|
|
|
|
else:
|
|
|
|
|
yp = ifft(hstack((xx, zeros_like(xx[..., 0]), conj(xx[..., :0:-1]))))
|
|
|
|
|
y = yp[..., :n]
|
|
|
|
|
|
|
|
|
|
if real_x:
|
|
|
|
|
return y.real
|
|
|
|
|
else:
|
|
|
|
|
return y
|
|
|
|
|
return _idct(x, n=n, norm=None)*0.5/len(x)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _chebval(x, ck, kind=1):
|
|
|
|
@ -1792,7 +1803,7 @@ def padefitlsq(fun, m, k, a=-1, b=1, trace=False, x=None, end_points=True):
|
|
|
|
|
|
|
|
|
|
smallest_devmax = BIG
|
|
|
|
|
ncof = m + k + 1
|
|
|
|
|
# % Number of points where function is evaluated, i.e. fineness of mesh
|
|
|
|
|
# Number of points where function is evaluated, i.e. fineness of mesh
|
|
|
|
|
npt = NFAC * ncof
|
|
|
|
|
|
|
|
|
|
if x is None:
|
|
|
|
@ -1848,7 +1859,7 @@ def padefitlsq(fun, m, k, a=-1, b=1, trace=False, x=None, end_points=True):
|
|
|
|
|
|
|
|
|
|
wt = np.abs(ee)
|
|
|
|
|
devmax = max(wt)
|
|
|
|
|
mad = wt.mean() # % mean absolute deviation
|
|
|
|
|
mad = wt.mean() # mean absolute deviation
|
|
|
|
|
|
|
|
|
|
# Save only the best coefficients found
|
|
|
|
|
if (devmax <= smallest_devmax):
|
|
|
|
@ -1940,9 +1951,362 @@ def test_docstrings():
|
|
|
|
|
doctest.testmod(optionflags=doctest.NORMALIZE_WHITESPACE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def chebvandernd(deg, *xi):
|
|
|
|
|
"""Pseudo-Vandermonde matrix of given degrees.
|
|
|
|
|
|
|
|
|
|
Returns the pseudo-Vandermonde matrix of degrees `deg` and sample
|
|
|
|
|
points `(x1, x2, ..., xn)`. If `l, m, n` are the given degrees in
|
|
|
|
|
`x1, x2, x3`, then The pseudo-Vandermonde matrix is defined by
|
|
|
|
|
|
|
|
|
|
.. math:: V[..., (m+1)(n+1)i + (n+1)j + k] = T_i(x1)*T_j(x2)*T_k(x3),
|
|
|
|
|
|
|
|
|
|
where `0 <= i <= l`, `0 <= j <= m`, and `0 <= k <= n`. The leading
|
|
|
|
|
indices of `V` index the points `(x, y, z)` and the last index encodes
|
|
|
|
|
the degrees of the Chebyshev polynomials.
|
|
|
|
|
|
|
|
|
|
If ``V = chebvandernd([xdeg, ydeg, zdeg], x, y, z)``, then the columns
|
|
|
|
|
of `V` correspond to the elements of a 3-D coefficient array `c` of
|
|
|
|
|
shape (xdeg + 1, ydeg + 1, zdeg + 1) in the order
|
|
|
|
|
|
|
|
|
|
.. math:: c_{000}, c_{001}, c_{002},... , c_{010}, c_{011}, c_{012},...
|
|
|
|
|
|
|
|
|
|
and ``np.dot(V, c.flat)`` and ``chebvalnd(c, x, y, z)`` will be the
|
|
|
|
|
same up to roundoff. This equivalence is useful both for least squares
|
|
|
|
|
fitting and for the evaluation of a large number of N-D Chebyshev
|
|
|
|
|
series of the same degrees and sample points.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
deg : list of ints
|
|
|
|
|
List of maximum degrees of the form [x1_deg, x2_deg, ...,xn_deg].
|
|
|
|
|
x1, x2, ..., xn : array_like
|
|
|
|
|
Arrays of point coordinates, all of the same shape. The dtypes will
|
|
|
|
|
be converted to either float64 or complex128 depending on whether
|
|
|
|
|
any of the elements are complex. Scalars are converted to 1-D
|
|
|
|
|
arrays.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
vander : ndarray
|
|
|
|
|
The shape of the returned matrix is ``x1.shape + (order,)``, where
|
|
|
|
|
:math:`order = (deg[0]+1)*(deg([1]+1)*...*(deg[n-1]+1)`. The dtype will
|
|
|
|
|
be the same as the converted `x1`, `x2`, ... `xn`.
|
|
|
|
|
|
|
|
|
|
See Also
|
|
|
|
|
--------
|
|
|
|
|
chebvander, chebvalnd, chebfitnd
|
|
|
|
|
"""
|
|
|
|
|
ideg = [int(d) for d in deg]
|
|
|
|
|
is_valid = np.array([id == d and id >= 0 for id, d in zip(ideg, deg)])
|
|
|
|
|
if np.any(is_valid != 1):
|
|
|
|
|
raise ValueError("degrees must be non-negative integers")
|
|
|
|
|
ndim = len(xi)
|
|
|
|
|
if len(ideg)!=ndim:
|
|
|
|
|
raise ValueError('length of deg must be the same as number of dimensions')
|
|
|
|
|
|
|
|
|
|
xi = np.array(xi, copy=0) + 0.0
|
|
|
|
|
chebvander = np.polynomial.chebyshev.chebvander
|
|
|
|
|
shape0 = xi[0].shape
|
|
|
|
|
s0 = (1,) * ndim
|
|
|
|
|
vxi = [chebvander(x, d).reshape(shape0 + s0[:i] + (-1,) + s0[i + 1::])
|
|
|
|
|
for i, (d, x) in enumerate(zip(ideg, xi))]
|
|
|
|
|
|
|
|
|
|
v = reduce(np.multiply, vxi)
|
|
|
|
|
|
|
|
|
|
return v.reshape(v.shape[:-ndim] + (-1,))
|
|
|
|
|
|
|
|
|
|
def chebfitnd(xi, f, deg, rcond=None, full=False, w=None):
|
|
|
|
|
"""
|
|
|
|
|
Least squares fit of Chebyshev series to N-dimensional data.
|
|
|
|
|
Return the coefficients of a Chebyshev series of degree `deg` that is the
|
|
|
|
|
least squares fit to the data values `f` given at points `x1`, `x2`,..., `xn`
|
|
|
|
|
|
|
|
|
|
The fitted polynomial(s) are in the form
|
|
|
|
|
.. math:: p(x,y) = c_00 + c_11 * T_1(x)*T_1(y) + ..c_ij * T_i(x)*T_j(y).
|
|
|
|
|
+ c_nm * T_n(x)*T_m(y),
|
|
|
|
|
where `n`, `m` is `deg`.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
xi: tuple
|
|
|
|
|
x1-, x2-,....xn-coordinates of the sample points.
|
|
|
|
|
f : array_like
|
|
|
|
|
function values at the sample points ``(x1[i], x2[i], ..., xn[i])``.
|
|
|
|
|
deg : list
|
|
|
|
|
Degrees of the fitting series in the x1, x2, ..., xn directions, respectively.
|
|
|
|
|
rcond : float, optional
|
|
|
|
|
Relative condition number of the fit. Singular values smaller than
|
|
|
|
|
this relative to the largest singular value will be ignored. The
|
|
|
|
|
default value is size(x1)*eps, where eps is the relative precision of
|
|
|
|
|
the float type, about 2e-16 in most cases.
|
|
|
|
|
full : bool, optional
|
|
|
|
|
Switch determining nature of return value. When it is False (the
|
|
|
|
|
default) just the coefficients are returned, when True diagnostic
|
|
|
|
|
information from the singular value decomposition is also returned.
|
|
|
|
|
w : array_like, optional
|
|
|
|
|
Weights. If not None, the contribution of each point
|
|
|
|
|
``(x1[i], x2[i], ..., xn[i])`` to the fit is weighted by `w[i]`.
|
|
|
|
|
Ideally the weights are chosen so that the errors of the products
|
|
|
|
|
``w[i]*f[i]`` all have the same variance. The default value is None.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
coef : ndarray, shape (M1, M2,..., Mn)
|
|
|
|
|
Chebyshev coefficients ordered from low to high.
|
|
|
|
|
[residuals, rank, singular_values, rcond] : list
|
|
|
|
|
These values are only returned if `full` = True
|
|
|
|
|
resid -- sum of squared residuals of the least squares fit
|
|
|
|
|
rank -- the numerical rank of the scaled Vandermonde matrix
|
|
|
|
|
sv -- singular values of the scaled Vandermonde matrix
|
|
|
|
|
rcond -- value of `rcond`.
|
|
|
|
|
For more details, see `linalg.lstsq`.
|
|
|
|
|
Warns
|
|
|
|
|
-----
|
|
|
|
|
RankWarning
|
|
|
|
|
The rank of the coefficient matrix in the least-squares fit is
|
|
|
|
|
deficient. The warning is only raised if `full` = False. The
|
|
|
|
|
warnings can be turned off by
|
|
|
|
|
>>> import warnings
|
|
|
|
|
>>> warnings.simplefilter('ignore', RankWarning)
|
|
|
|
|
|
|
|
|
|
See Also
|
|
|
|
|
--------
|
|
|
|
|
chebvalnd, chebgridnd
|
|
|
|
|
|
|
|
|
|
Notes
|
|
|
|
|
-----
|
|
|
|
|
The solution is the coefficients of the Chebyshev series `p` that
|
|
|
|
|
minimizes the sum of the weighted squared errors
|
|
|
|
|
.. math:: E = \\sum_j w_j^2 * |y_j - p(x_j)|^2,
|
|
|
|
|
where :math:`w_j` are the weights. This problem is solved by setting up
|
|
|
|
|
as the (typically) overdetermined matrix equation
|
|
|
|
|
.. math:: V(x, y) * c = w * y,
|
|
|
|
|
where `V` is the weighted pseudo Vandermonde matrix of `x`, `c` are the
|
|
|
|
|
coefficients to be solved for, `w` are the weights, and `y` are the
|
|
|
|
|
observed values. This equation is then solved using the singular value
|
|
|
|
|
decomposition of `V`.
|
|
|
|
|
If some of the singular values of `V` are so small that they are
|
|
|
|
|
neglected, then a `RankWarning` will be issued. This means that the
|
|
|
|
|
coefficient values may be poorly determined. Using a lower order fit
|
|
|
|
|
will usually get rid of the warning. The `rcond` parameter can also be
|
|
|
|
|
set to a value smaller than its default, but the resulting fit may be
|
|
|
|
|
spurious and have large contributions from roundoff error.
|
|
|
|
|
Fits using Chebyshev series are usually better conditioned than fits
|
|
|
|
|
using power series, but much can depend on the distribution of the
|
|
|
|
|
sample points and the smoothness of the data. If the quality of the fit
|
|
|
|
|
is inadequate splines may be a good alternative.
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
----------
|
|
|
|
|
.. [1] Wikipedia, "Curve fitting",
|
|
|
|
|
http://en.wikipedia.org/wiki/Curve_fitting
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
"""
|
|
|
|
|
xi_ = np.array(xi, copy=0) + 0.0
|
|
|
|
|
z = np.array(f)
|
|
|
|
|
degrees = np.asarray(deg, dtype=int)
|
|
|
|
|
orders = degrees + 1
|
|
|
|
|
order = np.product(orders)
|
|
|
|
|
|
|
|
|
|
ndims = np.array([x.ndim for x in xi])
|
|
|
|
|
ndim = len(ndims)
|
|
|
|
|
sizes = np.array([x.size for x in xi])
|
|
|
|
|
if np.any(ndims!=ndim) or z.ndim!=ndim:
|
|
|
|
|
raise TypeError("expected %dD array for x1, x2,...,xn and f" % ndim)
|
|
|
|
|
if np.any(sizes == 0):
|
|
|
|
|
raise TypeError("expected non-empty vector for xi")
|
|
|
|
|
|
|
|
|
|
lhs = chebvandernd(degrees, *xi).reshape((-1, order))
|
|
|
|
|
rhs = z.ravel()
|
|
|
|
|
if w is not None:
|
|
|
|
|
w = np.asarray(w).ravel() + 0.0
|
|
|
|
|
if len(lhs) != len(w):
|
|
|
|
|
raise TypeError("expected x and w to have same length")
|
|
|
|
|
lhs = lhs * w
|
|
|
|
|
rhs = rhs * w
|
|
|
|
|
|
|
|
|
|
if rcond is None:
|
|
|
|
|
rcond = xi[0].size * np.finfo(x.dtype).eps
|
|
|
|
|
|
|
|
|
|
if issubclass(lhs.dtype.type, np.complexfloating):
|
|
|
|
|
scl = np.sqrt((np.square(lhs.real) + np.square(lhs.imag)).sum(axis=0))
|
|
|
|
|
else:
|
|
|
|
|
scl = np.sqrt(np.square(lhs).sum(axis=0))
|
|
|
|
|
scl[scl == 0] = 1
|
|
|
|
|
|
|
|
|
|
# Solve the least squares problem.
|
|
|
|
|
c, resids, rank, s = np.linalg.lstsq(lhs/scl, rhs, rcond)
|
|
|
|
|
c = (c/scl).reshape(orders)
|
|
|
|
|
|
|
|
|
|
if rank != order and not full:
|
|
|
|
|
msg = "The fit may be poorly conditioned"
|
|
|
|
|
warnings.warn(msg, pu.RankWarning)
|
|
|
|
|
|
|
|
|
|
if full:
|
|
|
|
|
return c, [resids, rank, s, rcond]
|
|
|
|
|
else:
|
|
|
|
|
return c
|
|
|
|
|
|
|
|
|
|
def chebvalnd(c, *xi):
|
|
|
|
|
"""
|
|
|
|
|
Evaluate a N-D Chebyshev series at points (x1, x2, ..., xn).
|
|
|
|
|
|
|
|
|
|
This function returns the values:
|
|
|
|
|
|
|
|
|
|
.. math:: p(x1,x2,...,xn) = \\sum_{i,j,...,k} c_{i,j,...,k} * T_i(x1) * T_j(x2)*...* T_k(xn)
|
|
|
|
|
|
|
|
|
|
The parameters `x1`, `x2`, ...., `xn` are converted to arrays only if
|
|
|
|
|
they are tuples or a lists, otherwise they are treated as a scalars and
|
|
|
|
|
they must have the same shape after conversion. In either case, either
|
|
|
|
|
`x1`, `x2`, ..., `xn` or their elements must support multiplication and
|
|
|
|
|
addition both with themselves and with the elements of `c`.
|
|
|
|
|
|
|
|
|
|
If `c` has fewer than N dimensions, ones are implicitly appended to its
|
|
|
|
|
shape to make it N-D. The shape of the result will be c.shape[3:] +
|
|
|
|
|
x1.shape.
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
c : array_like
|
|
|
|
|
Array of coefficients ordered so that the coefficient of the term of
|
|
|
|
|
multi-degree i,j,...,k is contained in ``c[i,j,...,k]``. If `c` has
|
|
|
|
|
dimension greater than N the remaining indices enumerate multiple sets of
|
|
|
|
|
coefficients.
|
|
|
|
|
x1, x2,..., xn : array_like, compatible object
|
|
|
|
|
The N dimensional series is evaluated at the points
|
|
|
|
|
`(x1, x2,...,xn)`, where `x1`, `x2`,..., `xn` must have the same shape.
|
|
|
|
|
If any of `x1`, `x2`, ..., `xn` is a list or tuple, it is first converted
|
|
|
|
|
to an ndarray, otherwise it is left unchanged and if it isn't an
|
|
|
|
|
ndarray it is treated as a scalar.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
values : ndarray, compatible object
|
|
|
|
|
The values of the multidimensional polynomial on points formed with
|
|
|
|
|
triples of corresponding values from `x`, `y`, and `z`.
|
|
|
|
|
|
|
|
|
|
See Also
|
|
|
|
|
--------
|
|
|
|
|
chebval, chebgridnd, chebfitnd
|
|
|
|
|
"""
|
|
|
|
|
try:
|
|
|
|
|
xi = np.array(xi, copy=0)
|
|
|
|
|
except:
|
|
|
|
|
raise ValueError('x, y, z are incompatible')
|
|
|
|
|
chebval = np.polynomial.chebyshev.chebval
|
|
|
|
|
c = chebval(xi[0], c)
|
|
|
|
|
for x in xi[1:]:
|
|
|
|
|
c = chebval(x, c, tensor=False)
|
|
|
|
|
return c
|
|
|
|
|
|
|
|
|
|
def chebgridnd(c, *xi):
|
|
|
|
|
"""
|
|
|
|
|
Evaluate a N-D Chebyshev series on the Cartesian product of x1, x2,..., xn.
|
|
|
|
|
|
|
|
|
|
This function returns the values:
|
|
|
|
|
|
|
|
|
|
.. math:: p(a,b,...) = \\sum_{i,j,...} c_{i,j,...} * T_i(a) * T_j(b) * ...
|
|
|
|
|
|
|
|
|
|
where the points `(a, b, ...)` consist of all points formed by taking
|
|
|
|
|
`a` from `x1`, `b` from `x2`, and so on. The resulting points form
|
|
|
|
|
a grid with `x1` in the first dimension, `x2` in the second, and so on.
|
|
|
|
|
|
|
|
|
|
The parameters `x1`, `x2`, ... and `xn` are converted to arrays only if they
|
|
|
|
|
are tuples or a lists, otherwise they are treated as a scalars. In
|
|
|
|
|
either case, either `x1`, `x2`,... and `xn` or their elements must support
|
|
|
|
|
multiplication and addition both with themselves and with the elements
|
|
|
|
|
of `c`.
|
|
|
|
|
|
|
|
|
|
If `c` has fewer than N dimensions, ones are implicitly appended to
|
|
|
|
|
its shape to make it N-D. The shape of the result will be c.shape[3:] +
|
|
|
|
|
x1.shape + x2.shape + ... + xn.shape
|
|
|
|
|
|
|
|
|
|
Parameters
|
|
|
|
|
----------
|
|
|
|
|
c : array_like
|
|
|
|
|
Array of coefficients ordered so that the coefficients for terms of
|
|
|
|
|
degree i,j are contained in ``c[i,j]``. If `c` has dimension
|
|
|
|
|
greater than two the remaining indices enumerate multiple sets of
|
|
|
|
|
coefficients.
|
|
|
|
|
x1, x2,..., xn : ndarray, compatible object
|
|
|
|
|
1-D arrays representing the coordinates of a grid.
|
|
|
|
|
The N dimensional series is evaluated at the points in the
|
|
|
|
|
Cartesian product of `x1`, `x2`, ... and `xn`. If `xi`, is a
|
|
|
|
|
list or tuple, it is first converted to an ndarray, otherwise it is
|
|
|
|
|
left unchanged and, if it isn't an ndarray, it is treated as a
|
|
|
|
|
scalar.
|
|
|
|
|
|
|
|
|
|
Returns
|
|
|
|
|
-------
|
|
|
|
|
values : ndarray, compatible object
|
|
|
|
|
The values of the N dimensional polynomial at points in the Cartesian
|
|
|
|
|
product of `x1`, `x2`, ... and `xn`.
|
|
|
|
|
|
|
|
|
|
See Also
|
|
|
|
|
--------
|
|
|
|
|
chebval, chebvalnd, chebfitnd
|
|
|
|
|
"""
|
|
|
|
|
chebval = np.polynomial.chebyshev.chebval
|
|
|
|
|
for x in xi:
|
|
|
|
|
c = chebval(x, c)
|
|
|
|
|
return c
|
|
|
|
|
|
|
|
|
|
def test_chebfit1d():
|
|
|
|
|
n = 63
|
|
|
|
|
x = chebroot(n=64, kind=1)
|
|
|
|
|
|
|
|
|
|
def f(x):
|
|
|
|
|
return np.exp(-x**2)
|
|
|
|
|
|
|
|
|
|
z = f(x)
|
|
|
|
|
|
|
|
|
|
c = chebfit(f, n=64)[::-1]
|
|
|
|
|
|
|
|
|
|
xi = np.linspace(-1, 1, 151)
|
|
|
|
|
zi = np.polynomial.chebyshev.chebval(xi, c)
|
|
|
|
|
|
|
|
|
|
#plt.plot(xi, zi,'.', xi, f(xi))
|
|
|
|
|
plt.semilogy(xi, np.abs(zi-f(xi)))
|
|
|
|
|
plt.show('hold')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_chebfit2d():
|
|
|
|
|
n = 3
|
|
|
|
|
xorder, yorder = n-1, n-1
|
|
|
|
|
x = chebroot(n=n, kind=1)
|
|
|
|
|
xgrid, ygrid = meshgrid(x, x)
|
|
|
|
|
def f(x, y):
|
|
|
|
|
return np.exp(-x**2-6*y**2)
|
|
|
|
|
zgrid = f(xgrid, ygrid)
|
|
|
|
|
|
|
|
|
|
#v2d = np.polynomial.chebyshev.chebvander2d(xgrid, ygrid, [xorder,yorder]).reshape((-1, (xorder+1)*(yorder+1)))
|
|
|
|
|
#coeff, residuals, rank, s = np.linalg.lstsq(v2d, zgrid.ravel())
|
|
|
|
|
#doeff = coeff.reshape(xorder+1,yorder+1)
|
|
|
|
|
dcoeff2 = chebfitnd((xgrid, ygrid), zgrid, [xorder,yorder])
|
|
|
|
|
dcoeff = chebfit_dct(f, n=(xorder+1,yorder+1))
|
|
|
|
|
|
|
|
|
|
xi = np.linspace(-1, 1, 151)
|
|
|
|
|
Xi,Yi = np.meshgrid(xi, xi)
|
|
|
|
|
Zi = f(Xi, Yi)
|
|
|
|
|
zzi = chebvalnd(dcoeff, Xi, Yi)
|
|
|
|
|
devi = Zi - zzi
|
|
|
|
|
# plot residuals
|
|
|
|
|
#zz = np.polynomial.chebyshev.chebval2d(xgrid, ygrid, dcoeff)
|
|
|
|
|
zz = chebvalnd(dcoeff, xgrid, ygrid)
|
|
|
|
|
dev = zgrid - zz
|
|
|
|
|
#plt.spy(np.abs(dcoeff)>1e-13)
|
|
|
|
|
plt.contourf(xgrid, ygrid, np.abs(dev))
|
|
|
|
|
#plt.contourf(Xi, Yi, np.abs(devi))
|
|
|
|
|
plt.colorbar()
|
|
|
|
|
# plt.semilogy(np.abs(devi.ravel()))
|
|
|
|
|
plt.show('hold')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
if False: # True: #
|
|
|
|
|
main()
|
|
|
|
|
else:
|
|
|
|
|
test_docstrings()
|
|
|
|
|
test_chebfit2d()
|
|
|
|
|
# test_docstrings()
|
|
|
|
|
# test_polydeg()
|
|
|
|
|