chebfun 0.4.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chebfun-0.4.4.1/.gitignore +39 -0
- chebfun-0.4.4.1/LICENSE.rst +13 -0
- chebfun-0.4.4.1/PKG-INFO +58 -0
- chebfun-0.4.4.1/README.rst +42 -0
- chebfun-0.4.4.1/chebpy/__init__.py +4 -0
- chebfun-0.4.4.1/chebpy/api.py +41 -0
- chebfun-0.4.4.1/chebpy/core/__init__.py +0 -0
- chebfun-0.4.4.1/chebpy/core/algorithms.py +326 -0
- chebfun-0.4.4.1/chebpy/core/bndfun.py +7 -0
- chebfun-0.4.4.1/chebpy/core/chebfun.py +440 -0
- chebfun-0.4.4.1/chebpy/core/chebtech.py +444 -0
- chebfun-0.4.4.1/chebpy/core/classicfun.py +322 -0
- chebfun-0.4.4.1/chebpy/core/decorators.py +131 -0
- chebfun-0.4.4.1/chebpy/core/exceptions.py +101 -0
- chebfun-0.4.4.1/chebpy/core/ffts.py +11 -0
- chebfun-0.4.4.1/chebpy/core/fun.py +165 -0
- chebfun-0.4.4.1/chebpy/core/importing.py +20 -0
- chebfun-0.4.4.1/chebpy/core/onefun.py +165 -0
- chebfun-0.4.4.1/chebpy/core/plotting.py +34 -0
- chebfun-0.4.4.1/chebpy/core/settings.py +57 -0
- chebfun-0.4.4.1/chebpy/core/smoothfun.py +7 -0
- chebfun-0.4.4.1/chebpy/core/utilities.py +269 -0
- chebfun-0.4.4.1/pyproject.toml +44 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
*.py[cod]
|
|
2
|
+
*.todo
|
|
3
|
+
*.ini
|
|
4
|
+
*~
|
|
5
|
+
*/.ipynb_checkpoints/*
|
|
6
|
+
|
|
7
|
+
# C extensions
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# Packages
|
|
11
|
+
*.egg
|
|
12
|
+
*.egg-info
|
|
13
|
+
dist
|
|
14
|
+
build
|
|
15
|
+
eggs
|
|
16
|
+
parts
|
|
17
|
+
bin
|
|
18
|
+
var
|
|
19
|
+
sdist
|
|
20
|
+
develop-eggs
|
|
21
|
+
.installed.cfg
|
|
22
|
+
lib
|
|
23
|
+
lib64
|
|
24
|
+
|
|
25
|
+
# Installer logs
|
|
26
|
+
pip-log.txt
|
|
27
|
+
|
|
28
|
+
# Unit test / coverage reports
|
|
29
|
+
.coverage
|
|
30
|
+
.tox
|
|
31
|
+
nosetests.xml
|
|
32
|
+
lcov.info
|
|
33
|
+
|
|
34
|
+
*.DS_Store
|
|
35
|
+
*.dylib
|
|
36
|
+
*.pyc
|
|
37
|
+
.idea/
|
|
38
|
+
docs/_*
|
|
39
|
+
pdoc
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Copyright (c) 2016: Mark Richardson and other contributors:
|
|
2
|
+
|
|
3
|
+
https://github.com/chebpy/chebpy/graphs/contributors
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
8
|
+
|
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
10
|
+
|
|
11
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
12
|
+
|
|
13
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
chebfun-0.4.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chebfun
|
|
3
|
+
Version: 0.4.4.1
|
|
4
|
+
Summary: A Python implementation of Chebfun
|
|
5
|
+
Project-URL: repository, https://github.com/chebpy/chebpy
|
|
6
|
+
Author-email: Mark Richardson <mrichardson82@gmail.com>
|
|
7
|
+
License-File: LICENSE.rst
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: numpy>=2.0
|
|
10
|
+
Provides-Extra: dev
|
|
11
|
+
Requires-Dist: matplotlib==3.10.0; extra == 'dev'
|
|
12
|
+
Requires-Dist: pre-commit>=4.2.0; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest-cov>=6.2.1; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest>=8.4.1; extra == 'dev'
|
|
15
|
+
Description-Content-Type: text/x-rst
|
|
16
|
+
|
|
17
|
+
================================================
|
|
18
|
+
ChebPy - A Python implementation of Chebfun
|
|
19
|
+
================================================
|
|
20
|
+
|
|
21
|
+
.. image:: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml/badge.svg
|
|
22
|
+
:target: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml
|
|
23
|
+
.. image:: https://coveralls.io/repos/github/chebpy/chebpy/badge.svg?branch=master
|
|
24
|
+
:target: https://coveralls.io/github/chebpy/chebpy?branch=master
|
|
25
|
+
.. image:: https://img.shields.io/badge/python-%203.8_--%203.13-blue.svg?
|
|
26
|
+
:target: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml
|
|
27
|
+
.. image:: https://img.shields.io/conda/dn/conda-forge/chebfun?label=conda%20downloads
|
|
28
|
+
:target: https://anaconda.org/conda-forge/chebfun
|
|
29
|
+
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
30
|
+
:target: https://github.com/psf/black
|
|
31
|
+
.. image:: https://mybinder.org/badge_logo.svg
|
|
32
|
+
:target: https://mybinder.org/v2/gh/chebpy/chebpy/v0.4.3?filepath=docs%2Fnotebook-getting-started.ipynb
|
|
33
|
+
|
|
34
|
+
|
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
Numerical computing with Chebyshev series approximations in Python.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
.. image:: docs/chebpy-readme-image1.png
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
ChebPy is a Python implementation of `Chebfun <http://www.chebfun.org/>`_.
|
|
44
|
+
|
|
45
|
+
- The software is licensed under a 3-Clause BSD License, see `LICENSE.rst <LICENSE.rst>`_.
|
|
46
|
+
- For installation details, see `INSTALL.rst <INSTALL.rst>`_.
|
|
47
|
+
- The code is documented in various files in the `docs <docs/>`_ folder.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
The figure above was generated with the following simple ChebPy code:
|
|
51
|
+
|
|
52
|
+
.. code:: python
|
|
53
|
+
|
|
54
|
+
f = chebfun(lambda x: np.sin(x**2) + np.sin(x)**2, [0, 10])
|
|
55
|
+
g = chebfun(lambda x: np.exp(-(x-5)**2/10), [0, 10])
|
|
56
|
+
r = (f-g).roots()
|
|
57
|
+
ax = f.plot(); g.plot()
|
|
58
|
+
ax.plot(r, f(r), 'o')
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
================================================
|
|
2
|
+
ChebPy - A Python implementation of Chebfun
|
|
3
|
+
================================================
|
|
4
|
+
|
|
5
|
+
.. image:: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml/badge.svg
|
|
6
|
+
:target: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml
|
|
7
|
+
.. image:: https://coveralls.io/repos/github/chebpy/chebpy/badge.svg?branch=master
|
|
8
|
+
:target: https://coveralls.io/github/chebpy/chebpy?branch=master
|
|
9
|
+
.. image:: https://img.shields.io/badge/python-%203.8_--%203.13-blue.svg?
|
|
10
|
+
:target: https://github.com/chebpy/chebpy/actions/workflows/unittest.yml
|
|
11
|
+
.. image:: https://img.shields.io/conda/dn/conda-forge/chebfun?label=conda%20downloads
|
|
12
|
+
:target: https://anaconda.org/conda-forge/chebfun
|
|
13
|
+
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
|
14
|
+
:target: https://github.com/psf/black
|
|
15
|
+
.. image:: https://mybinder.org/badge_logo.svg
|
|
16
|
+
:target: https://mybinder.org/v2/gh/chebpy/chebpy/v0.4.3?filepath=docs%2Fnotebook-getting-started.ipynb
|
|
17
|
+
|
|
18
|
+
|
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
Numerical computing with Chebyshev series approximations in Python.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
.. image:: docs/chebpy-readme-image1.png
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
ChebPy is a Python implementation of `Chebfun <http://www.chebfun.org/>`_.
|
|
28
|
+
|
|
29
|
+
- The software is licensed under a 3-Clause BSD License, see `LICENSE.rst <LICENSE.rst>`_.
|
|
30
|
+
- For installation details, see `INSTALL.rst <INSTALL.rst>`_.
|
|
31
|
+
- The code is documented in various files in the `docs <docs/>`_ folder.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
The figure above was generated with the following simple ChebPy code:
|
|
35
|
+
|
|
36
|
+
.. code:: python
|
|
37
|
+
|
|
38
|
+
f = chebfun(lambda x: np.sin(x**2) + np.sin(x)**2, [0, 10])
|
|
39
|
+
g = chebfun(lambda x: np.exp(-(x-5)**2/10), [0, 10])
|
|
40
|
+
r = (f-g).roots()
|
|
41
|
+
ax = f.plot(); g.plot()
|
|
42
|
+
ax.plot(r, f(r), 'o')
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""User-facing functions"""
|
|
2
|
+
|
|
3
|
+
from .core.bndfun import Bndfun
|
|
4
|
+
from .core.chebfun import Chebfun
|
|
5
|
+
from .core.utilities import Domain
|
|
6
|
+
from .core.settings import _preferences as prefs
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def chebfun(f=None, domain=None, n=None):
|
|
10
|
+
"""Chebfun constructor"""
|
|
11
|
+
# chebfun()
|
|
12
|
+
if f is None:
|
|
13
|
+
return Chebfun.initempty()
|
|
14
|
+
|
|
15
|
+
domain = domain if domain is not None else prefs.domain
|
|
16
|
+
|
|
17
|
+
# chebfun(lambda x: f(x), ... )
|
|
18
|
+
if hasattr(f, "__call__"):
|
|
19
|
+
return Chebfun.initfun(f, domain, n)
|
|
20
|
+
|
|
21
|
+
# chebfun('x', ... )
|
|
22
|
+
if isinstance(f, str) and len(f) == 1 and f.isalpha():
|
|
23
|
+
if n:
|
|
24
|
+
return Chebfun.initfun(lambda x: x, domain, n)
|
|
25
|
+
else:
|
|
26
|
+
return Chebfun.initidentity(domain)
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
# chebfun(3.14, ... ), chebfun('3.14', ... )
|
|
30
|
+
return Chebfun.initconst(float(f), domain)
|
|
31
|
+
except (OverflowError, ValueError):
|
|
32
|
+
raise ValueError(f"Unable to construct const function from {{{f}}}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def pwc(domain=[-1, 0, 1], values=[0, 1]):
|
|
36
|
+
"""Initialise a piecewise-constant Chebfun"""
|
|
37
|
+
funs = []
|
|
38
|
+
intervals = [x for x in Domain(domain).intervals]
|
|
39
|
+
for interval, value in zip(intervals, values):
|
|
40
|
+
funs.append(Bndfun.initconst(value, interval))
|
|
41
|
+
return Chebfun(funs)
|
|
File without changes
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from .ffts import fft, ifft
|
|
6
|
+
from .utilities import Interval, infnorm
|
|
7
|
+
from .settings import _preferences as prefs
|
|
8
|
+
from .decorators import preandpostprocess
|
|
9
|
+
|
|
10
|
+
# supress numpy division and multiply warnings
|
|
11
|
+
np.seterr(divide="ignore", invalid="ignore")
|
|
12
|
+
|
|
13
|
+
# constants
|
|
14
|
+
SPLITPOINT = -0.004849834917525
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# local helpers
|
|
18
|
+
def find(x):
|
|
19
|
+
return np.where(x)[0]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def rootsunit(ak, htol=None):
|
|
23
|
+
"""Compute the roots of a funciton on [-1,1] using the coefficeints
|
|
24
|
+
in the associated Chebyshev series representation.
|
|
25
|
+
|
|
26
|
+
References
|
|
27
|
+
----------
|
|
28
|
+
.. [1] I. J. Good, "The colleague matrix, a Chebyshev analogue of the
|
|
29
|
+
companion matrix", Quarterly Journal of Mathematics 12 (1961).
|
|
30
|
+
|
|
31
|
+
.. [2] J. A. Boyd, "Computing zeros on a real interval through
|
|
32
|
+
Chebyshev expansion and polynomial rootfinding", SIAM Journal on
|
|
33
|
+
Numerical Analysis 40 (2002).
|
|
34
|
+
|
|
35
|
+
.. [3] L. N. Trefethen, Approximation Theory and Approximation
|
|
36
|
+
Practice, SIAM, 2013, chapter 18.
|
|
37
|
+
"""
|
|
38
|
+
htol = htol if htol is not None else 1e2 * prefs.eps
|
|
39
|
+
n = standard_chop(ak, tol=htol)
|
|
40
|
+
ak = ak[:n]
|
|
41
|
+
|
|
42
|
+
# if n > 50, we split and recurse
|
|
43
|
+
if n > 50:
|
|
44
|
+
chebpts = chebpts2(ak.size)
|
|
45
|
+
lmap = Interval(-1, SPLITPOINT)
|
|
46
|
+
rmap = Interval(SPLITPOINT, 1)
|
|
47
|
+
lpts = lmap(chebpts)
|
|
48
|
+
rpts = rmap(chebpts)
|
|
49
|
+
lval = clenshaw(lpts, ak)
|
|
50
|
+
rval = clenshaw(rpts, ak)
|
|
51
|
+
lcfs = vals2coeffs2(lval)
|
|
52
|
+
rcfs = vals2coeffs2(rval)
|
|
53
|
+
lrts = rootsunit(lcfs, 2 * htol)
|
|
54
|
+
rrts = rootsunit(rcfs, 2 * htol)
|
|
55
|
+
return np.append(lmap(lrts), rmap(rrts))
|
|
56
|
+
|
|
57
|
+
# trivial base case
|
|
58
|
+
if n <= 1:
|
|
59
|
+
return np.array([])
|
|
60
|
+
|
|
61
|
+
# nontrivial base case: either compute directly or solve
|
|
62
|
+
# a Colleague Matrix eigenvalue problem
|
|
63
|
+
if n == 2:
|
|
64
|
+
rts = np.array([-ak[0] / ak[1]])
|
|
65
|
+
elif n <= 50:
|
|
66
|
+
v = 0.5 * np.ones(n - 2)
|
|
67
|
+
C = np.diag(v, -1) + np.diag(v, 1)
|
|
68
|
+
C[0, 1] = 1
|
|
69
|
+
D = np.zeros(C.shape, dtype=ak.dtype)
|
|
70
|
+
D[-1, :] = ak[:-1]
|
|
71
|
+
E = C - 0.5 * 1.0 / ak[-1] * D
|
|
72
|
+
rts = np.linalg.eigvals(E)
|
|
73
|
+
|
|
74
|
+
# discard values with large imaginary part and treat the remaining
|
|
75
|
+
# ones as real; then sort and retain only the roots inside [-1,1]
|
|
76
|
+
mask = abs(np.imag(rts)) < htol
|
|
77
|
+
rts = np.real(rts[mask])
|
|
78
|
+
rts = rts[abs(rts) <= 1.0 + htol]
|
|
79
|
+
rts = np.sort(rts)
|
|
80
|
+
if rts.size >= 2:
|
|
81
|
+
rts[0] = max([rts[0], -1])
|
|
82
|
+
rts[-1] = min([rts[-1], 1])
|
|
83
|
+
return rts
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@preandpostprocess
|
|
87
|
+
def bary(xx, fk, xk, vk):
|
|
88
|
+
"""Barycentric interpolation formula. See:
|
|
89
|
+
|
|
90
|
+
J.P. Berrut, L.N. Trefethen, Barycentric Lagrange Interpolation, SIAM
|
|
91
|
+
Review (2004)
|
|
92
|
+
|
|
93
|
+
Inputs
|
|
94
|
+
------
|
|
95
|
+
xx : numpy ndarray
|
|
96
|
+
array of evaluation points
|
|
97
|
+
fk : numpy ndarray
|
|
98
|
+
array of function values at the interpolation nodes xk
|
|
99
|
+
xk: numpy ndarray
|
|
100
|
+
array of interpolation nodes
|
|
101
|
+
vk: numpy ndarray
|
|
102
|
+
barycentric weights corresponding to the interpolation nodes xk
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
# either iterate over the evaluation points, or ...
|
|
106
|
+
if xx.size < 4 * xk.size:
|
|
107
|
+
out = np.zeros(xx.size)
|
|
108
|
+
for i in range(xx.size):
|
|
109
|
+
tt = vk / (xx[i] - xk)
|
|
110
|
+
out[i] = np.dot(tt, fk) / tt.sum()
|
|
111
|
+
|
|
112
|
+
# ... iterate over the barycenters
|
|
113
|
+
else:
|
|
114
|
+
numer = np.zeros(xx.size)
|
|
115
|
+
denom = np.zeros(xx.size)
|
|
116
|
+
for j in range(xk.size):
|
|
117
|
+
temp = vk[j] / (xx - xk[j])
|
|
118
|
+
numer = numer + temp * fk[j]
|
|
119
|
+
denom = denom + temp
|
|
120
|
+
out = numer / denom
|
|
121
|
+
|
|
122
|
+
# replace NaNs
|
|
123
|
+
for k in find(np.isnan(out)):
|
|
124
|
+
idx = find(xx[k] == xk)
|
|
125
|
+
if idx.size > 0:
|
|
126
|
+
out[k] = fk[idx[0]]
|
|
127
|
+
|
|
128
|
+
return out
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@preandpostprocess
|
|
132
|
+
def clenshaw(xx, ak):
|
|
133
|
+
"""Clenshaw's algorithm for the evaluation of a first-kind Chebyshev
|
|
134
|
+
series expansion at some array of points x"""
|
|
135
|
+
bk1 = 0 * xx
|
|
136
|
+
bk2 = 0 * xx
|
|
137
|
+
xx = 2 * xx
|
|
138
|
+
idx = range(ak.size)
|
|
139
|
+
for k in idx[ak.size : 1 : -2]:
|
|
140
|
+
bk2 = ak[k] + xx * bk1 - bk2
|
|
141
|
+
bk1 = ak[k - 1] + xx * bk2 - bk1
|
|
142
|
+
if np.mod(ak.size - 1, 2) == 1:
|
|
143
|
+
bk1, bk2 = ak[1] + xx * bk1 - bk2, bk1
|
|
144
|
+
out = ak[0] + 0.5 * xx * bk1 - bk2
|
|
145
|
+
return out
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def standard_chop(coeffs, tol=None):
|
|
149
|
+
"""Chop a Chebyshev series to a given tolerance. This is a Python
|
|
150
|
+
transcription of the algorithm described in:
|
|
151
|
+
|
|
152
|
+
J. Aurentz and L.N. Trefethen, Chopping a Chebyshev series (2015)
|
|
153
|
+
(http://arxiv.org/pdf/1512.01803v1.pdf)
|
|
154
|
+
"""
|
|
155
|
+
|
|
156
|
+
# check magnitude of tol:
|
|
157
|
+
tol = tol if tol is not None else prefs.eps
|
|
158
|
+
if tol >= 1:
|
|
159
|
+
cutoff = 1
|
|
160
|
+
return cutoff
|
|
161
|
+
|
|
162
|
+
# ensure length at least 17:
|
|
163
|
+
n = coeffs.size
|
|
164
|
+
cutoff = n
|
|
165
|
+
if n < 17:
|
|
166
|
+
return cutoff
|
|
167
|
+
|
|
168
|
+
# Step 1: Convert coeffs input to a new monotonically nonincreasing
|
|
169
|
+
# vector (envelope) normalized to begin with the value 1.
|
|
170
|
+
b = np.flipud(np.abs(coeffs))
|
|
171
|
+
m = np.flipud(np.maximum.accumulate(b))
|
|
172
|
+
if m[0] == 0.0:
|
|
173
|
+
# TODO: check this
|
|
174
|
+
cutoff = 1 # cutoff = 0
|
|
175
|
+
return cutoff
|
|
176
|
+
envelope = m / m[0]
|
|
177
|
+
|
|
178
|
+
# Step 2: Scan envelope for a value plateauPoint, the first point, if any,
|
|
179
|
+
# that is followed by a plateau
|
|
180
|
+
for j in np.arange(1, n):
|
|
181
|
+
j2 = round(1.25 * j + 5)
|
|
182
|
+
if j2 > n - 1:
|
|
183
|
+
# there is no plateau: exit
|
|
184
|
+
return cutoff
|
|
185
|
+
e1 = envelope[j]
|
|
186
|
+
e2 = envelope[int(j2)]
|
|
187
|
+
r = 3 * (1 - np.log(e1) / np.log(tol))
|
|
188
|
+
plateau = (e1 == 0.0) | (e2 / e1 > r)
|
|
189
|
+
if plateau:
|
|
190
|
+
# a plateau has been found: go to Step 3
|
|
191
|
+
plateauPoint = j
|
|
192
|
+
break
|
|
193
|
+
|
|
194
|
+
# Step 3: Fix cutoff at a point where envelope, plus a linear function
|
|
195
|
+
# included to bias the result towards the left end, is minimal.
|
|
196
|
+
if envelope[int(plateauPoint)] == 0.0:
|
|
197
|
+
cutoff = plateauPoint
|
|
198
|
+
else:
|
|
199
|
+
j3 = sum(envelope >= tol ** (7.0 / 6.0))
|
|
200
|
+
if j3 < j2:
|
|
201
|
+
j2 = j3 + 1
|
|
202
|
+
envelope[j2] = tol ** (7.0 / 6.0)
|
|
203
|
+
cc = np.log10(envelope[: int(j2)])
|
|
204
|
+
cc = cc + np.linspace(0, (-1.0 / 3.0) * np.log10(tol), int(j2))
|
|
205
|
+
d = np.argmin(cc)
|
|
206
|
+
# TODO: check this
|
|
207
|
+
cutoff = d # + 2
|
|
208
|
+
return min((cutoff, n - 1))
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def adaptive(cls, fun, hscale=1, maxpow2=None):
|
|
212
|
+
"""Adaptive constructor: cycle over powers of two, calling
|
|
213
|
+
standard_chop each time, the output of which determines whether or not
|
|
214
|
+
we are happy."""
|
|
215
|
+
minpow2 = 4 # 17 points
|
|
216
|
+
maxpow2 = maxpow2 if maxpow2 is not None else prefs.maxpow2
|
|
217
|
+
for k in range(minpow2, max(minpow2, maxpow2) + 1):
|
|
218
|
+
n = 2**k + 1
|
|
219
|
+
points = cls._chebpts(n)
|
|
220
|
+
values = fun(points)
|
|
221
|
+
coeffs = cls._vals2coeffs(values)
|
|
222
|
+
eps = prefs.eps
|
|
223
|
+
tol = eps * max(hscale, 1) # scale (decrease) tolerance by hscale
|
|
224
|
+
chplen = standard_chop(coeffs, tol=tol)
|
|
225
|
+
if chplen < coeffs.size:
|
|
226
|
+
coeffs = coeffs[:chplen]
|
|
227
|
+
break
|
|
228
|
+
if k == maxpow2:
|
|
229
|
+
warnings.warn("The {} constructor did not converge: using {} points".format(cls.__name__, n))
|
|
230
|
+
break
|
|
231
|
+
return coeffs
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def coeffmult(fc, gc):
|
|
235
|
+
"""Coefficient-Space multiplication of equal-length first-kind
|
|
236
|
+
Chebyshev series."""
|
|
237
|
+
Fc = np.append(2.0 * fc[:1], (fc[1:], fc[:0:-1]))
|
|
238
|
+
Gc = np.append(2.0 * gc[:1], (gc[1:], gc[:0:-1]))
|
|
239
|
+
ak = ifft(fft(Fc) * fft(Gc))
|
|
240
|
+
ak = np.append(ak[:1], ak[1:] + ak[:0:-1]) * 0.25
|
|
241
|
+
ak = ak[: fc.size]
|
|
242
|
+
inputcfs = np.append(fc, gc)
|
|
243
|
+
out = np.real(ak) if np.isreal(inputcfs).all() else ak
|
|
244
|
+
return out
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def barywts2(n):
|
|
248
|
+
"""Barycentric weights for Chebyshev points of 2nd kind"""
|
|
249
|
+
if n == 0:
|
|
250
|
+
wts = np.array([])
|
|
251
|
+
elif n == 1:
|
|
252
|
+
wts = np.array([1])
|
|
253
|
+
else:
|
|
254
|
+
wts = np.append(np.ones(n - 1), 0.5)
|
|
255
|
+
wts[n - 2 :: -2] = -1
|
|
256
|
+
wts[0] = 0.5 * wts[0]
|
|
257
|
+
return wts
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def chebpts2(n):
|
|
261
|
+
"""Return n Chebyshev points of the second-kind"""
|
|
262
|
+
if n == 1:
|
|
263
|
+
pts = np.array([0.0])
|
|
264
|
+
else:
|
|
265
|
+
nn = np.arange(n)
|
|
266
|
+
pts = np.cos(nn[::-1] * np.pi / (n - 1))
|
|
267
|
+
return pts
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def vals2coeffs2(vals):
|
|
271
|
+
"""Map function values at Chebyshev points of 2nd kind to
|
|
272
|
+
first-kind Chebyshev polynomial coefficients"""
|
|
273
|
+
n = vals.size
|
|
274
|
+
if n <= 1:
|
|
275
|
+
coeffs = vals
|
|
276
|
+
return coeffs
|
|
277
|
+
tmp = np.append(vals[::-1], vals[1:-1])
|
|
278
|
+
if np.isreal(vals).all():
|
|
279
|
+
coeffs = ifft(tmp)
|
|
280
|
+
coeffs = np.real(coeffs)
|
|
281
|
+
elif np.isreal(1j * vals).all():
|
|
282
|
+
coeffs = ifft(np.imag(tmp))
|
|
283
|
+
coeffs = 1j * np.real(coeffs)
|
|
284
|
+
else:
|
|
285
|
+
coeffs = ifft(tmp)
|
|
286
|
+
coeffs = coeffs[:n]
|
|
287
|
+
coeffs[1 : n - 1] = 2 * coeffs[1 : n - 1]
|
|
288
|
+
return coeffs
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def coeffs2vals2(coeffs):
|
|
292
|
+
"""Map first-kind Chebyshev polynomial coefficients to
|
|
293
|
+
function values at Chebyshev points of 2nd kind"""
|
|
294
|
+
n = coeffs.size
|
|
295
|
+
if n <= 1:
|
|
296
|
+
vals = coeffs
|
|
297
|
+
return vals
|
|
298
|
+
coeffs = coeffs.copy()
|
|
299
|
+
coeffs[1 : n - 1] = 0.5 * coeffs[1 : n - 1]
|
|
300
|
+
tmp = np.append(coeffs, coeffs[n - 2 : 0 : -1])
|
|
301
|
+
if np.isreal(coeffs).all():
|
|
302
|
+
vals = fft(tmp)
|
|
303
|
+
vals = np.real(vals)
|
|
304
|
+
elif np.isreal(1j * coeffs).all():
|
|
305
|
+
vals = fft(np.imag(tmp))
|
|
306
|
+
vals = 1j * np.real(vals)
|
|
307
|
+
else:
|
|
308
|
+
vals = fft(tmp)
|
|
309
|
+
vals = vals[n - 1 :: -1]
|
|
310
|
+
return vals
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def newtonroots(fun, rts, tol=None, maxiter=None):
|
|
314
|
+
"""Rootfinding for a callable and differentiable fun, typically used to
|
|
315
|
+
polish already computed roots."""
|
|
316
|
+
tol = tol if tol is not None else 2 * prefs.eps
|
|
317
|
+
maxiter = maxiter if maxiter is not None else prefs.maxiter
|
|
318
|
+
if rts.size > 0:
|
|
319
|
+
dfun = fun.diff()
|
|
320
|
+
prv = np.inf * rts
|
|
321
|
+
count = 0
|
|
322
|
+
while (infnorm(rts - prv) > tol) & (count <= maxiter):
|
|
323
|
+
count += 1
|
|
324
|
+
prv = rts
|
|
325
|
+
rts = rts - fun(rts) / dfun(rts)
|
|
326
|
+
return rts
|