Coverage for src/chebpy/api.py: 97%
70 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-22 21:50 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-22 21:50 +0000
1"""User-facing functions for creating and manipulating Chebfun objects.
3This module provides the main interface for users to create Chebfun objects,
4which are the core data structure in ChebPy for representing functions.
5"""
7from collections.abc import Callable
8from typing import Any
10import numpy as np
12from .algorithms import barywts2, chebpts2, funqui
13from .bndfun import Bndfun
14from .chebfun import Chebfun
15from .settings import _preferences as prefs
16from .utilities import Domain, Interval
19def chebfun(
20 f: Callable[..., Any] | str | float | None = None,
21 domain: np.ndarray | list[float] | None = None,
22 n: int | None = None,
23 *,
24 sing: str | None = None,
25 params: Any = None,
26) -> "Chebfun":
27 """Create a Chebfun object representing a function.
29 A Chebfun object represents a function using Chebyshev polynomials. This constructor
30 can create Chebfun objects from various inputs including callable functions,
31 constants, and special strings.
33 Args:
34 f: The function to represent. Can be:
35 - None: Creates an empty Chebfun
36 - callable: A function handle like lambda x: x**2
37 - str: A single alphabetic character (e.g., 'x') for the identity function
38 - numeric: A constant value
39 domain: The domain on which to define the function. Defaults to the domain
40 specified in preferences.
41 n: Optional number of points to use in the discretization. If None, adaptive
42 construction is used.
43 sing: Optional endpoint-singularity hint, one of ``"left"``, ``"right"``,
44 or ``"both"``. When set, the appropriate boundary pieces are built
45 as :class:`~chebpy.singfun.Singfun` instances using the
46 Adcock-Richardson exponential clustering map; interior pieces remain
47 :class:`~chebpy.bndfun.Bndfun`. Only supported with ``n=None``.
48 params: Slit-strip map parameters (a :class:`~chebpy.maps.MapParams`
49 carrying ``L`` and ``alpha``). Default ``None`` uses
50 :class:`~chebpy.maps.MapParams` defaults.
52 Returns:
53 Chebfun: A Chebfun object representing the function.
55 Raises:
56 ValueError: If unable to construct a constant function from the input.
58 Examples:
59 >>> # Empty Chebfun
60 >>> f = chebfun()
61 >>>
62 >>> # Function from a lambda
63 >>> import numpy as np
64 >>> f = chebfun(lambda x: np.sin(x), domain=[-np.pi, np.pi])
65 >>>
66 >>> # Identity function
67 >>> x = chebfun('x')
68 >>>
69 >>> # Constant function
70 >>> c = chebfun(3.14)
71 >>>
72 >>> # Function with an endpoint singularity
73 >>> g = chebfun(np.sqrt, domain=[0.0, 1.0], sing="left")
74 """
75 # Empty via chebfun()
76 if f is None:
77 return Chebfun.initempty()
79 domain = domain if domain is not None else prefs.domain
81 # Callable fct in chebfun(lambda x: f(x), ... )
82 if callable(f):
83 return Chebfun.initfun(f, domain, n, sing=sing, params=params)
85 # Identity via chebfun('x', ... )
86 if isinstance(f, str) and len(f) == 1 and f.isalpha():
87 if n:
88 return Chebfun.initfun(lambda x: x, domain, n)
89 else:
90 return Chebfun.initidentity(domain)
92 try:
93 # Constant fct via chebfun(3.14, ... ), chebfun('3.14', ... )
94 return Chebfun.initconst(float(f), domain)
95 except (OverflowError, ValueError) as err:
96 raise ValueError(f) from err
99def equifun(values: np.ndarray | list[float | complex], domain: np.ndarray | list[float] | None = None) -> "Chebfun":
100 """Create a Chebfun from equispaced samples including both endpoints.
102 Args:
103 values: Non-empty one-dimensional sample values.
104 domain: Two finite endpoints for the sample interval. Defaults to
105 the configured preference domain.
107 Returns:
108 Chebfun: A scalar-valued Chebfun approximating the Floater-Hormann
109 rational interpolant through the equispaced samples.
111 Raises:
112 ValueError: If values are empty, non-numeric, not one-dimensional, or
113 if domain is not exactly two finite endpoints.
115 Examples:
116 >>> import numpy as np
117 >>> from chebpy import equifun
118 >>> x = np.linspace(-1, 1, 25)
119 >>> f = equifun(np.sin(x))
120 >>> bool(abs(f(0.0)) < 1e-12)
121 True
122 """
123 vals = np.asarray(values)
124 if vals.size == 0:
125 msg = "values must be non-empty"
126 raise ValueError(msg)
127 if vals.ndim != 1:
128 msg = "values must be one-dimensional"
129 raise ValueError(msg)
130 if not np.issubdtype(vals.dtype, np.number):
131 msg = "values must be numeric"
132 raise ValueError(msg)
134 dom = np.asarray(prefs.domain if domain is None else domain, dtype=float)
135 if dom.ndim != 1 or dom.size != 2:
136 msg = "domain must contain exactly two endpoints"
137 raise ValueError(msg)
138 if not np.all(np.isfinite(dom)):
139 msg = "domain endpoints must be finite"
140 raise ValueError(msg)
141 if dom[0] >= dom[1]:
142 msg = "domain endpoints must be strictly increasing"
143 raise ValueError(msg)
144 dom = Domain(dom)
146 if vals.size == 1:
147 value = complex(vals[0]) if np.iscomplexobj(vals) else vals[0]
148 return Chebfun.initconst(value, dom)
149 return Chebfun.initfun(funqui(vals, dom), dom)
152def pwc(domain: list[float] | None = None, values: list[float] | None = None) -> "Chebfun":
153 """Initialize a piecewise-constant Chebfun.
155 Creates a piecewise-constant function represented as a Chebfun object.
156 The function takes constant values on each interval defined by the domain.
158 Args:
159 domain (list): A list of breakpoints defining the intervals. Must have
160 length equal to len(values) + 1. Default is [-1, 0, 1].
161 values (list): A list of constant values for each interval. Default is [0, 1].
163 Returns:
164 Chebfun: A piecewise-constant Chebfun object.
166 Examples:
167 >>> # Create a step function with value 0 on [-1,0] and 1 on [0,1]
168 >>> f = pwc()
169 >>>
170 >>> # Create a custom piecewise-constant function
171 >>> f = pwc(domain=[-2, -1, 0, 1, 2], values=[-1, 0, 1, 2])
172 """
173 if values is None:
174 values = [0, 1]
175 if domain is None:
176 domain = [-1, 0, 1]
177 funs: list[Any] = []
178 intervals = list(Domain(domain).intervals)
179 for interval, value in zip(intervals, values, strict=False):
180 funs.append(Bndfun.initconst(value, interval))
181 return Chebfun(funs)
184def chebpts(
185 n: int,
186 domain: list[float] | None = None,
187) -> tuple[np.ndarray, np.ndarray]:
188 """Return *n* Chebyshev points and barycentric weights on *domain*.
190 This provides the same functionality as MATLAB's ``chebpts(n, [a, b])``.
191 The points are Chebyshev points of the second kind (i.e. the extrema of
192 the Chebyshev polynomial T_{n-1} plus the endpoints).
194 Args:
195 n: Number of Chebyshev points.
196 domain: Two-element list ``[a, b]`` specifying the interval.
197 Defaults to ``[-1, 1]``.
199 Returns:
200 A ``(points, weights)`` tuple where *points* is an array of *n*
201 Chebyshev points on the given domain and *weights* is the
202 corresponding array of barycentric interpolation weights.
204 Examples:
205 >>> pts, wts = chebpts(4)
206 >>> pts, wts = chebpts(4, [0, 3])
207 """
208 if domain is None:
209 domain = [-1, 1]
210 pts = chebpts2(n)
211 wts = barywts2(n)
212 interval = Interval(*domain)
213 pts = interval(pts)
214 return pts, wts
217def trigfun(
218 f: Callable[..., Any] | str | float | None = None,
219 domain: np.ndarray | list[float] | None = None,
220 n: int | None = None,
221) -> "Chebfun":
222 """Create a Chebfun backed by Fourier (trigonometric) technology.
224 This is the explicit entry point for constructing periodic functions.
225 Unlike ``chebfun``, which always uses Chebyshev polynomial technology,
226 ``trigfun`` always uses :class:`~chebpy.trigtech.Trigtech` as the
227 underlying approximation technology. The user is responsible for
228 ensuring that *f* is smooth and periodic on *domain*.
230 The API mirrors :func:`chebfun` exactly:
232 * ``trigfun()`` → empty Chebfun
233 * ``trigfun(lambda x: np.sin(np.pi*x), [-1, 1])`` → from callable
234 * ``trigfun('x')`` → identity (not truly periodic; provided for
235 interface compatibility)
236 * ``trigfun(3.14)`` → constant function
238 Args:
239 f: The function to represent. Same semantics as :func:`chebfun`.
240 domain: Domain ``[a, b]``. Defaults to ``prefs.domain``.
241 n: Fixed number of Fourier modes. If None, adaptive construction
242 is used.
244 Returns:
245 Chebfun: A Chebfun object whose pieces are backed by Trigtech.
247 Examples:
248 >>> import numpy as np
249 >>> from chebpy import trigfun
250 >>> f = trigfun(lambda x: np.cos(np.pi * x), [-1, 1])
251 >>> float(f(0.0))
252 1.0
253 >>> g = trigfun(lambda x: np.sin(2 * np.pi * x))
254 >>> bool(abs(g.sum()) < 1e-12)
255 True
256 """
257 with prefs:
258 prefs.tech = "Trigtech"
259 return chebfun(f, domain, n)