Find real roots of a polynomial in the interval [0, 1]. For polynomials of degree <= 2, closed-form solutions are used. For higher degrees, `numpy.roots` is used as a fallback. In practice, matplotlib only ever uses cubic bezier curves and axis_aligned_extrema() differentiates,
(coeffs)
| 41 | |
| 42 | |
| 43 | def _real_roots_in_01(coeffs): |
| 44 | """ |
| 45 | Find real roots of a polynomial in the interval [0, 1]. |
| 46 | |
| 47 | For polynomials of degree <= 2, closed-form solutions are used. |
| 48 | For higher degrees, `numpy.roots` is used as a fallback. In practice, |
| 49 | matplotlib only ever uses cubic bezier curves and axis_aligned_extrema() |
| 50 | differentiates, so we only ever find roots for degree <= 2. |
| 51 | |
| 52 | Parameters |
| 53 | ---------- |
| 54 | coeffs : array-like |
| 55 | Polynomial coefficients in ascending order: |
| 56 | ``c[0] + c[1]*x + c[2]*x**2 + ...`` |
| 57 | Note this is the opposite convention from `numpy.roots`. |
| 58 | |
| 59 | Returns |
| 60 | ------- |
| 61 | roots : ndarray |
| 62 | Sorted array of real roots in [0, 1]. |
| 63 | """ |
| 64 | coeffs = np.asarray(coeffs, dtype=float) |
| 65 | |
| 66 | # Trim trailing near-zeros to get actual degree |
| 67 | deg = len(coeffs) - 1 |
| 68 | while deg > 0 and abs(coeffs[deg]) < 1e-12: |
| 69 | deg -= 1 |
| 70 | |
| 71 | if deg <= 0: |
| 72 | return np.array([]) |
| 73 | elif deg == 1: |
| 74 | root = -coeffs[0] / coeffs[1] |
| 75 | return np.array([root]) if 0 <= root <= 1 else np.array([]) |
| 76 | elif deg == 2: |
| 77 | roots = _quadratic_roots_in_01(coeffs[0], coeffs[1], coeffs[2]) |
| 78 | else: |
| 79 | # np.roots expects descending order (highest power first) |
| 80 | eps = 1e-10 |
| 81 | all_roots = np.roots(coeffs[deg::-1]) |
| 82 | real_mask = np.abs(all_roots.imag) < eps |
| 83 | real_roots = all_roots[real_mask].real |
| 84 | in_range = (real_roots >= -eps) & (real_roots <= 1 + eps) |
| 85 | roots = np.clip(real_roots[in_range], 0, 1) |
| 86 | |
| 87 | return np.sort(roots) |
| 88 | |
| 89 | |
| 90 | @lru_cache(maxsize=16) |
searching dependent graphs…