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
« prev ^ index » next coverage.py v7.3.2, created at 2024-03-28 07:59 +0000
1from typing import Optional
3import numpy as np
5# Epsilon as threshold
6EPS = 1e-5
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
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
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
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
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
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