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

27 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-01 13:43 +0000

1"""Construction of the piecewise fun list backing an ordinary Chebfun. 

2 

3Sibling of :mod:`chebpy._singular_construction`, which does the analogous job 

4for domains with endpoint singularities. Both live above the ``Bndfun`` / 

5``CompactFun`` layer because they dispatch between those representations, which 

6is why neither belongs in :mod:`chebpy.utilities`. 

7""" 

8 

9from __future__ import annotations 

10 

11import itertools 

12from collections.abc import Callable 

13from typing import Any 

14 

15import numpy as np 

16 

17from .compactfun import CompactFun 

18from .exceptions import InvalidDomain 

19from .settings import _preferences as prefs 

20from .utilities import Domain, Interval 

21 

22 

23def generate_funs( 

24 domain: Domain | list[float] | None, bndfun_constructor: Callable[..., Any], kwds: dict[str, Any] | None = None 

25) -> list[Any]: 

26 """Generate a collection of function objects over a domain. 

27 

28 This method is used by several of the Chebfun classmethod constructors to 

29 generate a collection of function objects over the specified domain. For 

30 pieces with finite endpoints the supplied ``bndfun_constructor`` is used; 

31 for pieces with one or both endpoints at ``±inf`` the corresponding 

32 classmethod on :class:`CompactFun` is invoked instead, dispatched by 

33 method name. 

34 

35 Args: 

36 domain (array-like or None): Domain breakpoints. If None, uses default domain from preferences. 

37 The outermost breakpoints may be ``±inf``; interior breakpoints must be finite. 

38 bndfun_constructor (callable): Constructor function for creating function objects on 

39 finite intervals (typically a :class:`Bndfun` classmethod). 

40 kwds (dict, optional): Additional keyword arguments to pass to the constructor. Defaults to {}. 

41 

42 Returns: 

43 list: List of function objects covering the domain. 

44 

45 Raises: 

46 InvalidDomain: If a piece has an infinite endpoint but 

47 ``bndfun_constructor`` has no matching :class:`CompactFun` 

48 classmethod to build it with. 

49 """ 

50 if kwds is None: 

51 kwds = {} 

52 domain = Domain(domain if domain is not None else prefs.domain) 

53 

54 method_name = getattr(bndfun_constructor, "__name__", None) 

55 compact_constructor: Callable[..., Any] | None = ( 

56 getattr(CompactFun, method_name) if method_name is not None and hasattr(CompactFun, method_name) else None 

57 ) 

58 

59 funs = [] 

60 for a, b in itertools.pairwise(domain): 

61 a_f, b_f = float(a), float(b) 

62 if np.isfinite(a_f) and np.isfinite(b_f): 

63 interval: Any = Interval(a_f, b_f) 

64 ctor = bndfun_constructor 

65 else: 

66 if compact_constructor is None: 

67 raise InvalidDomain 

68 interval = (a_f, b_f) # CompactFun classmethods accept (a, b) tuples with ±inf 

69 ctor = compact_constructor 

70 funs.append(ctor(**{**kwds, "interval": interval})) 

71 return funs