Coverage for src / chebpy / api.py: 100%

44 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-05-05 07:22 +0000

1"""User-facing functions for creating and manipulating Chebfun objects. 

2 

3This module provides the main interface for users to create Chebfun objects, 

4which are the core data structure in ChebPy for representing functions. 

5""" 

6 

7from collections.abc import Callable 

8from typing import Any 

9 

10import numpy as np 

11 

12from .algorithms import barywts2, chebpts2 

13from .bndfun import Bndfun 

14from .chebfun import Chebfun 

15from .settings import _preferences as prefs 

16from .utilities import Domain, Interval 

17 

18 

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. 

28 

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. 

32 

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. 

51 

52 Returns: 

53 Chebfun: A Chebfun object representing the function. 

54 

55 Raises: 

56 ValueError: If unable to construct a constant function from the input. 

57 

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() 

78 

79 domain = domain if domain is not None else prefs.domain 

80 

81 # Callable fct in chebfun(lambda x: f(x), ... ) 

82 if callable(f): 

83 return Chebfun.initfun(f, domain, n, sing=sing, params=params) 

84 

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) 

91 

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 

97 

98 

99def pwc(domain: list[float] | None = None, values: list[float] | None = None) -> "Chebfun": 

100 """Initialize a piecewise-constant Chebfun. 

101 

102 Creates a piecewise-constant function represented as a Chebfun object. 

103 The function takes constant values on each interval defined by the domain. 

104 

105 Args: 

106 domain (list): A list of breakpoints defining the intervals. Must have 

107 length equal to len(values) + 1. Default is [-1, 0, 1]. 

108 values (list): A list of constant values for each interval. Default is [0, 1]. 

109 

110 Returns: 

111 Chebfun: A piecewise-constant Chebfun object. 

112 

113 Examples: 

114 >>> # Create a step function with value 0 on [-1,0] and 1 on [0,1] 

115 >>> f = pwc() 

116 >>> 

117 >>> # Create a custom piecewise-constant function 

118 >>> f = pwc(domain=[-2, -1, 0, 1, 2], values=[-1, 0, 1, 2]) 

119 """ 

120 if values is None: 

121 values = [0, 1] 

122 if domain is None: 

123 domain = [-1, 0, 1] 

124 funs: list[Any] = [] 

125 intervals = list(Domain(domain).intervals) 

126 for interval, value in zip(intervals, values, strict=False): 

127 funs.append(Bndfun.initconst(value, interval)) 

128 return Chebfun(funs) 

129 

130 

131def chebpts( 

132 n: int, 

133 domain: list[float] | None = None, 

134) -> tuple[np.ndarray, np.ndarray]: 

135 """Return *n* Chebyshev points and barycentric weights on *domain*. 

136 

137 This provides the same functionality as MATLAB's ``chebpts(n, [a, b])``. 

138 The points are Chebyshev points of the second kind (i.e. the extrema of 

139 the Chebyshev polynomial T_{n-1} plus the endpoints). 

140 

141 Args: 

142 n: Number of Chebyshev points. 

143 domain: Two-element list ``[a, b]`` specifying the interval. 

144 Defaults to ``[-1, 1]``. 

145 

146 Returns: 

147 A ``(points, weights)`` tuple where *points* is an array of *n* 

148 Chebyshev points on the given domain and *weights* is the 

149 corresponding array of barycentric interpolation weights. 

150 

151 Examples: 

152 >>> pts, wts = chebpts(4) 

153 >>> pts, wts = chebpts(4, [0, 3]) 

154 """ 

155 if domain is None: 

156 domain = [-1, 1] 

157 pts = chebpts2(n) 

158 wts = barywts2(n) 

159 interval = Interval(*domain) 

160 pts = interval(pts) 

161 return pts, wts 

162 

163 

164def trigfun( 

165 f: Callable[..., Any] | str | float | None = None, 

166 domain: np.ndarray | list[float] | None = None, 

167 n: int | None = None, 

168) -> "Chebfun": 

169 """Create a Chebfun backed by Fourier (trigonometric) technology. 

170 

171 This is the explicit entry point for constructing periodic functions. 

172 Unlike ``chebfun``, which always uses Chebyshev polynomial technology, 

173 ``trigfun`` always uses :class:`~chebpy.trigtech.Trigtech` as the 

174 underlying approximation technology. The user is responsible for 

175 ensuring that *f* is smooth and periodic on *domain*. 

176 

177 The API mirrors :func:`chebfun` exactly: 

178 

179 * ``trigfun()`` → empty Chebfun 

180 * ``trigfun(lambda x: np.sin(np.pi*x), [-1, 1])`` → from callable 

181 * ``trigfun('x')`` → identity (not truly periodic; provided for 

182 interface compatibility) 

183 * ``trigfun(3.14)`` → constant function 

184 

185 Args: 

186 f: The function to represent. Same semantics as :func:`chebfun`. 

187 domain: Domain ``[a, b]``. Defaults to ``prefs.domain``. 

188 n: Fixed number of Fourier modes. If None, adaptive construction 

189 is used. 

190 

191 Returns: 

192 Chebfun: A Chebfun object whose pieces are backed by Trigtech. 

193 

194 Examples: 

195 >>> import numpy as np 

196 >>> from chebpy import trigfun 

197 >>> f = trigfun(lambda x: np.cos(np.pi * x), [-1, 1]) 

198 >>> float(f(0.0)) 

199 1.0 

200 >>> g = trigfun(lambda x: np.sin(2 * np.pi * x)) 

201 >>> bool(abs(g.sum()) < 1e-12) 

202 True 

203 """ 

204 with prefs: 

205 prefs.tech = "Trigtech" 

206 return chebfun(f, domain, n)