Coverage for src/chebpy/onefun.py: 100%
4 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"""Abstract base class for functions defined on the standard interval [-1, 1].
3This module provides the Onefun abstract base class, which defines the interface for
4all function representations on the standard interval [-1, 1] in ChebPy. It specifies
5the methods and properties that concrete function classes must implement.
7The Onefun class serves as the foundation for representing functions on the standard
8interval, with concrete implementations like Chebtech inheriting from it. Functions
9defined on arbitrary intervals are typically mapped to this standard interval for
10internal representation and manipulation.
11"""
13from abc import ABC, abstractmethod
14from typing import Any
16import numpy as np
19class Onefun(ABC):
20 """Abstract base class for functions defined on the interval [-1, 1].
22 This class defines the interface for all function representations on the
23 standard interval [-1, 1]. It serves as the base class for specific
24 implementations like Chebtech.
26 Concrete subclasses must implement all the abstract methods defined here,
27 which include constructors, algebraic operations, calculus operations,
28 and utility functions.
29 """
31 # --------------------------
32 # alternative constructors
33 # --------------------------
34 @classmethod
35 @abstractmethod
36 def initconst(cls, c: float, *, interval: Any = None) -> "Onefun": # pragma: no cover
37 """Initialize a constant function.
39 This constructor creates a function that represents a constant value
40 on the interval [-1, 1].
42 Args:
43 c: The constant value.
44 interval: Optional interval associated with the function (used by mapped subclasses).
46 Returns:
47 Onefun: A new instance representing the constant function f(x) = c.
48 """
49 raise NotImplementedError
51 @classmethod
52 @abstractmethod
53 def initempty(cls, *, interval: Any = None) -> "Onefun": # pragma: no cover
54 """Initialize an empty function.
56 This constructor creates an empty function representation, which is
57 useful as a placeholder or for special cases.
59 Args:
60 interval: Optional interval associated with the function (used by mapped subclasses).
62 Returns:
63 Onefun: A new empty instance.
64 """
65 raise NotImplementedError
67 @classmethod
68 @abstractmethod
69 def initidentity(cls) -> "Onefun": # pragma: no cover
70 """Initialize the identity function f(x) = x.
72 This constructor creates a function that represents f(x) = x
73 on the interval [-1, 1].
75 Returns:
76 Onefun: A new instance representing the identity function.
77 """
78 raise NotImplementedError
80 @classmethod
81 @abstractmethod
82 def initfun(cls, f: Any, n: Any = None, *, interval: Any = None) -> "Onefun": # pragma: no cover
83 """Initialize from a callable function.
85 This is a general constructor that delegates to either initfun_adaptive
86 or initfun_fixedlen based on the provided parameters.
88 Args:
89 f (callable): The function to be approximated.
90 n (int, optional): If provided, specifies the number of points to use.
91 If None, determines the number adaptively.
92 interval: Optional interval associated with the function (used by mapped subclasses).
94 Returns:
95 Onefun: A new instance representing the function f.
96 """
97 raise NotImplementedError
99 @classmethod
100 @abstractmethod
101 def initfun_adaptive(cls, f: Any) -> "Onefun": # pragma: no cover
102 """Initialize from a callable function using adaptive sampling.
104 This constructor determines the appropriate number of points needed to
105 represent the function to a specified tolerance using an adaptive algorithm.
107 Args:
108 f (callable): The function to be approximated.
110 Returns:
111 Onefun: A new instance representing the function f.
112 """
113 raise NotImplementedError
115 @classmethod
116 @abstractmethod
117 def initfun_fixedlen(cls, f: Any, n: int) -> "Onefun": # pragma: no cover
118 """Initialize from a callable function using a fixed number of points.
120 This constructor uses a specified number of points to represent the function,
121 rather than determining the number adaptively.
123 Args:
124 f (callable): The function to be approximated.
125 n (int): The number of points to use.
127 Returns:
128 Onefun: A new instance representing the function f.
129 """
130 raise NotImplementedError
132 @classmethod
133 @abstractmethod
134 def initvalues(cls, values: Any, *, interval: Any = None) -> "Onefun": # pragma: no cover
135 """Initialize from function values at Chebyshev points.
137 This constructor creates a function representation from values
138 at Chebyshev points.
140 Args:
141 values: Function values at Chebyshev points.
142 interval: Optional interval associated with the function (used by mapped subclasses).
144 Returns:
145 Onefun: A new instance representing the function with the given values.
146 """
147 raise NotImplementedError
149 # -------------------
150 # "private" methods
151 # -------------------
152 @abstractmethod
153 def __call__(self, x: Any) -> Any: # pragma: no cover
154 """Evaluate the function at points x.
156 This method evaluates the function at the specified points.
158 Args:
159 x (float or array-like): Points at which to evaluate the function.
160 These should be in the interval [-1, 1].
162 Returns:
163 float or array-like: The value(s) of the function at the specified point(s).
164 Returns a scalar if x is a scalar, otherwise an array of the same size as x.
165 """
166 raise NotImplementedError
168 @abstractmethod
169 def __init__(self) -> None: # pragma: no cover
170 """Initialize a new Onefun instance.
172 This method initializes a new function representation on the interval [-1, 1].
173 The specific initialization depends on the concrete subclass implementation.
174 """
175 raise NotImplementedError
177 @abstractmethod
178 def __repr__(self) -> str: # pragma: no cover
179 """Return a string representation of the function.
181 This method returns a string representation of the function that includes
182 relevant information about its representation.
184 Returns:
185 str: A string representation of the function.
186 """
187 raise NotImplementedError
189 # ----------------
190 # algebra
191 # ----------------
192 @abstractmethod
193 def __add__(self, other: Any) -> "Onefun": # pragma: no cover
194 """Add this function with another function or a scalar.
196 This method implements the addition operation between this function
197 and another function or a scalar.
199 Args:
200 other (Onefun or scalar): The function or scalar to add to this function.
202 Returns:
203 Onefun: A new function representing the sum.
204 """
205 raise NotImplementedError
207 @abstractmethod
208 def __mul__(self, other: Any) -> "Onefun": # pragma: no cover
209 """Multiply this function with another function or a scalar.
211 This method implements the multiplication operation between this function
212 and another function or a scalar.
214 Args:
215 other (Onefun or scalar): The function or scalar to multiply with this function.
217 Returns:
218 Onefun: A new function representing the product.
219 """
220 raise NotImplementedError
222 @abstractmethod
223 def __neg__(self) -> "Onefun": # pragma: no cover
224 """Return the negative of this function.
226 This method implements the unary negation operation for this function.
228 Returns:
229 Onefun: A new function representing -f(x).
230 """
231 raise NotImplementedError
233 @abstractmethod
234 def __pos__(self) -> "Onefun": # pragma: no cover
235 """Return the positive of this function (which is the function itself).
237 This method implements the unary plus operation for this function.
239 Returns:
240 Onefun: This function object (unchanged).
241 """
242 raise NotImplementedError
244 @abstractmethod
245 def __pow__(self, power: Any) -> "Onefun": # pragma: no cover
246 """Raise this function to a power.
248 This method implements the power operation for this function.
250 Args:
251 power (int, float, or Onefun): The exponent to which this function is raised.
253 Returns:
254 Onefun: A new function representing f(x)^power.
255 """
256 raise NotImplementedError
258 @abstractmethod
259 def __radd__(self, other: Any) -> "Onefun": # pragma: no cover
260 """Add a scalar or another function to this function (from the right).
262 This method is called when a scalar or another function is added to this function,
263 i.e., other + self.
265 Args:
266 other (scalar or Onefun): The scalar or function to add to this function.
268 Returns:
269 Onefun: A new function representing the sum.
270 """
271 raise NotImplementedError
273 @abstractmethod
274 def __rmul__(self, other: Any) -> "Onefun": # pragma: no cover
275 """Multiply a scalar or another function with this function (from the right).
277 This method is called when a scalar or another function is multiplied with this function,
278 i.e., other * self.
280 Args:
281 other (scalar or Onefun): The scalar or function to multiply with this function.
283 Returns:
284 Onefun: A new function representing the product.
285 """
286 raise NotImplementedError
288 @abstractmethod
289 def __rsub__(self, other: Any) -> "Onefun": # pragma: no cover
290 """Subtract this function from a scalar or another function.
292 This method is called when this function is subtracted from a scalar or another function,
293 i.e., other - self.
295 Args:
296 other (scalar or Onefun): The scalar or function from which to subtract this function.
298 Returns:
299 Onefun: A new function representing the difference.
300 """
301 raise NotImplementedError
303 @abstractmethod
304 def __sub__(self, other: Any) -> "Onefun": # pragma: no cover
305 """Subtract another function or a scalar from this function.
307 This method implements the subtraction operation between this function
308 and another function or a scalar.
310 Args:
311 other (Onefun or scalar): The function or scalar to subtract from this function.
313 Returns:
314 Onefun: A new function representing the difference.
315 """
316 raise NotImplementedError
318 # ---------------
319 # properties
320 # ---------------
321 @property
322 @abstractmethod
323 def coeffs(self) -> np.ndarray: # pragma: no cover
324 """Get the coefficients of the function representation.
326 This property returns the coefficients used in the function representation,
327 such as Chebyshev coefficients for a Chebyshev series.
329 Returns:
330 array-like: The coefficients of the function representation.
331 """
332 raise NotImplementedError
334 @property
335 @abstractmethod
336 def isconst(self) -> bool: # pragma: no cover
337 """Check if this function represents a constant.
339 This property determines whether the function is constant (i.e., f(x) = c
340 for some constant c) over the interval [-1, 1].
342 Returns:
343 bool: True if the function is constant, False otherwise.
344 """
345 raise NotImplementedError
347 @property
348 @abstractmethod
349 def isempty(self) -> bool: # pragma: no cover
350 """Check if this function is empty.
352 This property determines whether the function is empty, which is a special
353 state used as a placeholder or for special cases.
355 Returns:
356 bool: True if the function is empty, False otherwise.
357 """
358 raise NotImplementedError
360 @property
361 @abstractmethod
362 def size(self) -> int: # pragma: no cover
363 """Get the size of the function representation.
365 This property returns the number of coefficients or other measure of the
366 complexity of the function representation.
368 Returns:
369 int: The size of the function representation.
370 """
371 raise NotImplementedError
373 @property
374 @abstractmethod
375 def vscale(self) -> float: # pragma: no cover
376 """Get the vertical scale of the function.
378 This property returns a measure of the range of function values, typically
379 the maximum absolute value of the function on the interval [-1, 1].
381 Returns:
382 float: The vertical scale of the function.
383 """
384 raise NotImplementedError
386 # ---------------
387 # utilities
388 # ---------------
389 @abstractmethod
390 def copy(self) -> "Onefun": # pragma: no cover
391 """Create a deep copy of this function.
393 This method creates a new function that is a deep copy of this function,
394 ensuring that modifications to the copy do not affect the original.
396 Returns:
397 Onefun: A new function that is a deep copy of this function.
398 """
399 raise NotImplementedError
401 @abstractmethod
402 def imag(self) -> "Onefun": # pragma: no cover
403 """Get the imaginary part of this function.
405 This method returns a new function representing the imaginary part of this function.
406 If this function is real-valued, returns a zero function.
408 Returns:
409 Onefun: A new function representing the imaginary part of this function.
410 """
411 raise NotImplementedError
413 @abstractmethod
414 def prolong(self, n: int) -> "Onefun": # pragma: no cover
415 """Extend the function representation to a larger size.
417 This method extends the function representation to use more coefficients
418 or a higher degree, which can be useful for certain operations.
420 Args:
421 n (int): The new size for the function representation.
423 Returns:
424 Onefun: A new function with an extended representation.
425 """
426 raise NotImplementedError
428 @abstractmethod
429 def real(self) -> "Onefun": # pragma: no cover
430 """Get the real part of this function.
432 This method returns a new function representing the real part of this function.
433 If this function is already real-valued, returns this function.
435 Returns:
436 Onefun: A new function representing the real part of this function.
437 """
438 raise NotImplementedError
440 @abstractmethod
441 def simplify(self) -> "Onefun": # pragma: no cover
442 """Simplify the function representation.
444 This method simplifies the function representation by removing unnecessary
445 coefficients or reducing the degree, while maintaining the specified accuracy.
447 Returns:
448 Onefun: A new function with a simplified representation.
449 """
450 raise NotImplementedError
452 @abstractmethod
453 def values(self) -> np.ndarray: # pragma: no cover
454 """Get the values of the function at Chebyshev points.
456 This method returns the values of the function at Chebyshev points,
457 which can be useful for certain operations or for visualization.
459 Returns:
460 array-like: The values of the function at Chebyshev points.
461 """
462 raise NotImplementedError
464 # --------------
465 # rootfinding
466 # --------------
467 @abstractmethod
468 def roots(self) -> np.ndarray: # pragma: no cover
469 """Find the roots (zeros) of the function on [-1, 1].
471 This method computes the points where the function equals zero
472 within the interval [-1, 1].
474 Returns:
475 array-like: An array of the roots of the function in the interval [-1, 1],
476 sorted in ascending order.
477 """
478 raise NotImplementedError
480 # -------------
481 # calculus
482 # -------------
483 @abstractmethod
484 def sum(self) -> float: # pragma: no cover
485 """Compute the definite integral of the function over [-1, 1].
487 This method calculates the definite integral of the function
488 over the interval [-1, 1].
490 Returns:
491 float or complex: The definite integral of the function over [-1, 1].
492 """
493 raise NotImplementedError
495 @abstractmethod
496 def cumsum(self) -> "Onefun": # pragma: no cover
497 """Compute the indefinite integral of the function.
499 This method calculates the indefinite integral (antiderivative) of the function,
500 with the constant of integration chosen so that the indefinite integral
501 evaluates to 0 at x = -1.
503 Returns:
504 Onefun: A new function representing the indefinite integral of this function.
505 """
506 raise NotImplementedError
508 @abstractmethod
509 def diff(self) -> "Onefun": # pragma: no cover
510 """Compute the derivative of the function.
512 This method calculates the derivative of the function with respect to x.
514 Returns:
515 Onefun: A new function representing the derivative of this function.
516 """
517 raise NotImplementedError