Coverage for src/spectroflat/utils/polynomial.py: 75%

55 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2024-03-28 07:59 +0000

1from typing import Optional 

2 

3import numpy as np 

4 

5# Epsilon as threshold 

6EPS = 1e-5 

7 

8 

9def min_value(poly, interval: tuple = (None, None)) -> Optional[float]: 

10 """ 

11 Return the minimum value of the polynomial within the given range 

12 (or globally, if no range is given) 

13 """ 

14 xes, yes = _locally_extreme_values(poly, interval) 

15 if len(yes) > 1: 

16 return min(yes) 

17 if poly(xes[0] - EPS) > yes[0] and poly(xes[0] + EPS) > yes[0]: 

18 return yes[0] 

19 return None 

20 

21 

22def min_pos(poly, interval: tuple = (None, None)) -> Optional[float]: 

23 """ 

24 Return the position of the minimum of the polynomial within the given range 

25 (or globally, if no range is given) 

26 """ 

27 xes, yes = _locally_extreme_values(poly, interval) 

28 if len(yes) > 1: 

29 return xes[np.argmin(yes)] 

30 if poly(xes[0] - EPS) > yes[0] and poly(xes[0] + EPS) > yes[0]: 

31 return xes[0] 

32 return None 

33 

34 

35def max_value(poly, interval: tuple = (None, None)) -> Optional[float]: 

36 """ 

37 Return the maximum value of the polynomial within the given range 

38 (or globally, if no range is given) 

39 """ 

40 xes, yes = _locally_extreme_values(poly, interval) 

41 if len(yes) > 1: 

42 return max(yes) 

43 if poly(xes[0] - EPS) < yes[0] and poly(xes[0] + EPS) < yes[0]: 

44 return yes[0] 

45 return None 

46 

47 

48def max_pos(poly, interval: tuple = (None, None)) -> Optional[float]: 

49 """ 

50 Return the position of the maximum of the polynomial within the given range 

51 (or globally, if no range is given) 

52 """ 

53 xes, yes = _locally_extreme_values(poly, interval) 

54 if len(yes) > 1: 

55 return xes[np.argmax(yes)] 

56 if poly(xes[0] - EPS) < yes[0] and poly(xes[0] + EPS) < yes[0]: 

57 return xes[0] 

58 return None 

59 

60 

61def abs_max_value(poly, interval: tuple = (None, None)) -> float: 

62 """ 

63 Return the maximum of the absolute extreme values within the given range 

64 (or globally, if no range is given) 

65 """ 

66 xes, yes = _locally_extreme_values(poly, interval) 

67 if len(yes) > 1: 

68 return max(np.abs(yes)) 

69 if poly(xes[0] - EPS) > yes[0] and poly(xes[0] + EPS) > yes[0]: 

70 return np.abs(yes[0]) 

71 return 0 

72 

73 

74def _locally_extreme_values(poly, interval: tuple = (None, None)) -> tuple: 

75 points = [] 

76 if interval[0] is not None: 

77 points.append(interval[0]) 

78 d = poly.deriv() 

79 roots = d.roots() if callable(d.roots) else d.roots 

80 for x in roots: 

81 if interval[0] is not None and x < interval[0]: 

82 continue 

83 if interval[1] is not None and x > interval[1]: 

84 continue 

85 points.append(x) 

86 if interval[1] is not None: 

87 points.append(interval[1]) 

88 points.sort() 

89 values = [poly(x) for x in points] 

90 return points, values