← Назад к вопросам
Как построить параболу между точками при фиксированном интервале, если требуется не более одной точки на интервал и покрытие должно составлять 70%?
2.7 Senior🔥 31 комментариев
#Архитектура и паттерны#Другое
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Построение параболы с интервалами и ограничениями
Это задача интерполяции: найти плавную кривую (параболу) между заданными точками с соблюдением ограничений на интервалы и покрытие.
Понимание задачи
Условия:
- Фиксированный интервал между точками (X-координата)
- Не более одной точки на интервал
- Покрытие 70% означает, что нужно покрыть 70% от всего диапазона
Пример:
Интервалы: 0-10 10-20 20-30 30-40 40-50
Точки: ✓ ✓ ✓ (3 точки)
Покрытие: 3/5 * 100 = 60% (нужно ≥70%)
Решение с использованием полиномиальной интерполяции
import numpy as np
from scipy.interpolate import interp1d, CubicSpline
import matplotlib.pyplot as plt
from typing import List, Tuple
class ParabolaInterpolator:
"""Построение параболы между точками с ограничениями"""
def __init__(self, interval_width: float, min_coverage: float = 0.7):
"""
Args:
interval_width: ширина одного интервала
min_coverage: минимальное покрытие (0.0 - 1.0)
"""
self.interval_width = interval_width
self.min_coverage = min_coverage
def validate_coverage(self, points: List[Tuple[float, float]]) -> bool:
"""Проверить, достаточно ли точек для требуемого покрытия"""
if not points:
return False
x_values = [p[0] for p in points]
min_x = min(x_values)
max_x = max(x_values)
total_range = max_x - min_x
num_intervals = int(np.ceil(total_range / self.interval_width))
num_points = len(points)
coverage = num_points / num_intervals if num_intervals > 0 else 0
return coverage >= self.min_coverage
def build_parabola(self, points: List[Tuple[float, float]]) -> callable:
"""
Построить параболу (кубический сплайн) через точки
Args:
points: список (x, y) координат
Returns:
функция f(x) для получения Y по X
"""
if len(points) < 3:
raise ValueError('Нужно минимум 3 точки для построения кривой')
# Проверить покрытие
if not self.validate_coverage(points):
raise ValueError(f'Недостаточное покрытие: требуется ≥{self.min_coverage*100}%')
# Сортировать по X
points_sorted = sorted(points, key=lambda p: p[0])
x = np.array([p[0] for p in points_sorted])
y = np.array([p[1] for p in points_sorted])
# Использовать CubicSpline для гладкой кривой
# (параболу по 2 точкам, кубический сплайн по 3+)
if len(x) == 2:
# Линейная интерполяция
f = interp1d(x, y, kind='linear', fill_value='extrapolate')
elif len(x) == 3:
# Квадратичная интерполяция (парабола)
f = interp1d(x, y, kind='quadratic', fill_value='extrapolate')
else:
# Кубический сплайн для 4+ точек
f = CubicSpline(x, y)
return f
def get_coverage_info(self, points: List[Tuple[float, float]]) -> dict:
"""Получить информацию о покрытии"""
if not points:
return {'coverage': 0, 'num_intervals': 0, 'num_points': 0}
x_values = [p[0] for p in points]
min_x = min(x_values)
max_x = max(x_values)
total_range = max_x - min_x
num_intervals = int(np.ceil(total_range / self.interval_width))
num_points = len(points)
coverage = num_points / num_intervals if num_intervals > 0 else 0
return {
'coverage': coverage,
'coverage_percent': coverage * 100,
'num_intervals': num_intervals,
'num_points': num_points,
'min_x': min_x,
'max_x': max_x,
'range': total_range,
'meets_requirement': coverage >= self.min_coverage
}
# Пример 1: Основное использование
if __name__ == '__main__':
# Создать интерполятор
interpolator = ParabolaInterpolator(
interval_width=10,
min_coverage=0.7 # 70%
)
# Точки (x, y)
points = [
(0, 10),
(15, 25),
(30, 18),
(40, 35),
]
# Проверить покрытие
info = interpolator.get_coverage_info(points)
print(f'Покрытие: {info["coverage_percent"]:.1f}%')
print(f'Интервалы: {info["num_intervals"]}, Точек: {info["num_points"]}')
print(f'Требование соблюдено: {info["meets_requirement"]}')
# Построить параболу
try:
f = interpolator.build_parabola(points)
# Вычислить значения на кривой
x_range = np.linspace(0, 40, 100)
y_range = f(x_range)
# Визуализация
plt.figure(figsize=(10, 6))
plt.plot(x_range, y_range, 'b-', label='Интерполированная кривая')
plt.plot([p[0] for p in points], [p[1] for p in points], 'ro', markersize=8, label='Исходные точки')
plt.xlabel('X')
plt.ylabel('Y')
plt.title('Интерполяция параболой')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
except ValueError as e:
print(f'Ошибка: {e}')
Пример 2: Оптимальный выбор точек для 70% покрытия
class PointSelector:
"""Выбор оптимальных точек для достижения требуемого покрытия"""
def __init__(self, interval_width: float, min_coverage: float = 0.7):
self.interval_width = interval_width
self.min_coverage = min_coverage
def select_points_for_coverage(self, x_min: float, x_max: float) -> List[float]:
"""
Выбрать X координаты для достижения 70% покрытия
"""
total_range = x_max - x_min
num_intervals = int(np.ceil(total_range / self.interval_width))
num_points_needed = int(np.ceil(num_intervals * self.min_coverage))
# Распределить точки равномерно
points_x = np.linspace(x_min, x_max, num_points_needed)
return points_x.tolist()
def generate_synthetic_data(self, x_coords: List[float], noise_level: float = 0) -> List[Tuple[float, float]]:
"""
Сгенерировать Y значения (например, из модели)
"""
points = []
for x in x_coords:
# Пример: парабола y = 0.5*x^2 - 10*x + 50
y = 0.5 * x**2 - 10 * x + 50
# Добавить шум
if noise_level > 0:
y += np.random.normal(0, noise_level)
points.append((x, y))
return points
# Использование
selector = PointSelector(interval_width=10, min_coverage=0.7)
# Выбрать точки для диапазона 0-50
points_x = selector.select_points_for_coverage(0, 50)
print(f'Выбранные X координаты: {points_x}')
print(f'Количество точек: {len(points_x)}')
print(f'Покрытие: {len(points_x) / 5 * 100:.1f}%')
# Сгенерировать Y значения
points = selector.generate_synthetic_data(points_x, noise_level=2)
print(f'Точки: {points}')
Пример 3: Сравнение методов интерполяции
def compare_interpolation_methods(points: List[Tuple[float, float]]):
"""Сравнить разные методы интерполяции"""
points_sorted = sorted(points, key=lambda p: p[0])
x = np.array([p[0] for p in points_sorted])
y = np.array([p[1] for p in points_sorted])
x_range = np.linspace(x.min(), x.max(), 200)
plt.figure(figsize=(12, 8))
# 1. Линейная интерполяция
if len(x) >= 2:
f_linear = interp1d(x, y, kind='linear')
y_linear = f_linear(x_range)
plt.subplot(2, 2, 1)
plt.plot(x_range, y_linear, 'b-', label='Linear')
plt.plot(x, y, 'ro')
plt.title('Linear Interpolation')
plt.grid(True, alpha=0.3)
# 2. Квадратичная интерполяция (парабола)
if len(x) >= 3:
f_quadratic = interp1d(x, y, kind='quadratic')
y_quadratic = f_quadratic(x_range)
plt.subplot(2, 2, 2)
plt.plot(x_range, y_quadratic, 'g-', label='Quadratic')
plt.plot(x, y, 'ro')
plt.title('Quadratic (Parabola) Interpolation')
plt.grid(True, alpha=0.3)
# 3. Кубическая интерполяция
if len(x) >= 4:
f_cubic = CubicSpline(x, y)
y_cubic = f_cubic(x_range)
plt.subplot(2, 2, 3)
plt.plot(x_range, y_cubic, 'r-', label='Cubic Spline')
plt.plot(x, y, 'ro')
plt.title('Cubic Spline Interpolation')
plt.grid(True, alpha=0.3)
# 4. Полиномиальная интерполяция
if len(x) >= 2:
coeffs = np.polyfit(x, y, min(len(x)-1, 5)) # До 5й степени
poly = np.poly1d(coeffs)
y_poly = poly(x_range)
plt.subplot(2, 2, 4)
plt.plot(x_range, y_poly, 'm-', label='Polynomial')
plt.plot(x, y, 'ro')
plt.title(f'Polynomial (degree {len(coeffs)-1})')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# Тестовые данные
test_points = [(0, 5), (10, 20), (20, 15), (30, 25), (40, 10)]
compare_interpolation_methods(test_points)
Пример 4: Валидация и обработка ошибок
class RobustParabolaBuilder:
"""Построение параболы с полной валидацией"""
@staticmethod
def validate_points(points: List[Tuple[float, float]], interval_width: float) -> Tuple[bool, str]:
"""Полная валидация точек"""
if not points:
return False, 'Список точек пуст'
if len(points) < 2:
return False, 'Нужно минимум 2 точки'
# Проверить на дубликаты X координат
x_values = [p[0] for p in points]
if len(set(x_values)) != len(x_values):
return False, 'Дубликаты X координат'
# Проверить интервалы
sorted_points = sorted(points, key=lambda p: p[0])
for i in range(len(sorted_points) - 1):
dist = sorted_points[i+1][0] - sorted_points[i][0]
if dist < interval_width / 2:
return False, f'Точки слишком близко: {dist} < {interval_width/2}'
# Проверить Y значения (должны быть числа)
for x, y in points:
if not isinstance(y, (int, float)) or np.isnan(y):
return False, f'Некорректное Y значение: {y}'
return True, 'OK'
@staticmethod
def build_parabola_safe(points: List[Tuple[float, float]], interval_width: float = 10) -> Tuple[callable, dict]:
"""Безопасное построение параболы с полной диагностикой"""
# Валидация
valid, msg = RobustParabolaBuilder.validate_points(points, interval_width)
if not valid:
return None, {'error': msg}
try:
points_sorted = sorted(points, key=lambda p: p[0])
x = np.array([p[0] for p in points_sorted])
y = np.array([p[1] for p in points_sorted])
if len(x) == 2:
f = interp1d(x, y, kind='linear', fill_value='extrapolate')
elif len(x) == 3:
f = interp1d(x, y, kind='quadratic', fill_value='extrapolate')
else:
f = CubicSpline(x, y)
return f, {'success': True, 'num_points': len(points), 'message': 'Парабола успешно построена'}
except Exception as e:
return None, {'error': f'Ошибка при построении: {str(e)}'}
# Использование
points = [(0, 10), (15, 25), (30, 20), (45, 30)]
f, info = RobustParabolaBuilder.build_parabola_safe(points, interval_width=10)
if f:
print(f'Успех: {info}')
print(f'f(20) = {f(20)}')
else:
print(f'Ошибка: {info}')
Ключевые моменты
- Покрытие: num_points / num_intervals ≥ 0.7
- Интервалы: фиксированная ширина, одна точка максимум
- Интерполяция: используй CubicSpline для гладких кривых
- Валидация: проверяй дубликаты, пропуски, NaN значения
- Экстраполяция: используй fill_value='extrapolate' для выхода за границы