paper_quant_2/main.py

305 lines
12 KiB
Python
Raw Normal View History

2026-02-18 08:37:45 +00:00
import numpy as np
import matplotlib.pyplot as plt
2026-02-18 08:50:20 +00:00
from typing import Dict, List, Callable, Any, Optional
import networkx as nx
from functools import lru_cache
import sympy as sp
from collections import defaultdict
2026-02-18 08:37:45 +00:00
class Parameter:
2026-02-18 08:50:20 +00:00
"""Класс для представления параметра с его формулой и зависимостями"""
def __init__(self, name: str, formula: Callable, dependencies: List[str] = None,
description: str = "", units: str = ""):
self.name = name
self.formula = formula # Функция для вычисления параметра
self.dependencies = dependencies or [] # Список зависимых параметров
self.description = description
self.units = units
self.cache = {} # Кэш для мемоизации
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def calculate(self, x_values: np.ndarray, param_values: Dict[str, np.ndarray]) -> np.ndarray:
"""Вычисление значений параметра для заданных x"""
# Проверка кэша
cache_key = (tuple(x_values), tuple(sorted(param_values.items())))
if cache_key in self.cache:
return self.cache[cache_key]
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Вычисление
if self.dependencies:
# Подготовка аргументов для формулы
args = [x_values] + [param_values[dep] for dep in self.dependencies]
result = self.formula(*args)
2026-02-18 08:37:45 +00:00
else:
2026-02-18 08:50:20 +00:00
result = self.formula(x_values)
# Сохранение в кэш
self.cache[cache_key] = result
return result
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def clear_cache(self):
"""Очистка кэша параметра"""
self.cache.clear()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
class FormulaModel:
"""Основной класс для управления моделью с параметрами"""
2026-02-18 08:37:45 +00:00
def __init__(self):
self.parameters: Dict[str, Parameter] = {}
self.main_formula: Optional[Callable] = None
2026-02-18 08:50:20 +00:00
self.dependency_graph = nx.DiGraph()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def add_parameter(self, parameter: Parameter):
"""Добавление параметра в модель"""
self.parameters[parameter.name] = parameter
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Обновление графа зависимостей
self.dependency_graph.add_node(parameter.name)
for dep in parameter.dependencies:
self.dependency_graph.add_edge(dep, parameter.name)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Проверка на циклические зависимости
if not nx.is_directed_acyclic_graph(self.dependency_graph):
raise ValueError(f"Циклическая зависимость обнаружена при добавлении параметра {parameter.name}")
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def set_main_formula(self, formula: Callable, dependencies: List[str]):
"""Установка основной формулы модели"""
2026-02-18 08:37:45 +00:00
self.main_formula = formula
2026-02-18 08:50:20 +00:00
self.main_dependencies = dependencies
def get_calculation_order(self) -> List[str]:
"""Получение порядка вычисления параметров с учетом зависимостей"""
try:
return list(nx.topological_sort(self.dependency_graph))
except nx.NetworkXError:
raise ValueError("Невозможно определить порядок вычисления из-за циклических зависимостей")
def calculate_all_parameters(self, x_values: np.ndarray) -> Dict[str, np.ndarray]:
"""Вычисление всех параметров в правильном порядке"""
param_values = {}
calculation_order = self.get_calculation_order()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
for param_name in calculation_order:
if param_name in self.parameters:
2026-02-18 08:37:45 +00:00
param = self.parameters[param_name]
2026-02-18 08:50:20 +00:00
param_values[param_name] = param.calculate(x_values, param_values)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
return param_values
def calculate_main_formula(self, x_values: np.ndarray) -> np.ndarray:
"""Вычисление основной формулы"""
if self.main_formula is None:
raise ValueError("Основная формула не установлена")
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
param_values = self.calculate_all_parameters(x_values)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Подготовка аргументов для основной формулы
args = [x_values] + [param_values[dep] for dep in self.main_dependencies]
return self.main_formula(*args)
def clear_all_cache(self):
"""Очистка всех кэшей"""
for param in self.parameters.values():
param.clear_cache()
class Plotter:
"""Класс для построения графиков"""
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def __init__(self, model: FormulaModel):
self.model = model
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def plot_parameter(self, param_name: str, x_range: tuple = (-10, 10),
num_points: int = 1000, title: str = None):
"""График отдельного параметра"""
if param_name not in self.model.parameters:
raise ValueError(f"Параметр {param_name} не найден")
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
x_values = np.linspace(x_range[0], x_range[1], num_points)
param_values = self.model.calculate_all_parameters(x_values)
y_values = param_values[param_name]
plt.figure(figsize=(10, 6))
plt.plot(x_values, y_values, linewidth=2)
plt.grid(True, alpha=0.3)
param = self.model.parameters[param_name]
plt.title(title or f"Параметр {param_name}: {param.description}")
plt.xlabel("x")
plt.ylabel(f"{param_name} ({param.units})" if param.units else param_name)
plt.show()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
def plot_all_parameters(self, x_range: tuple = (-10, 10), num_points: int = 1000):
"""График всех параметров на одном рисунке"""
x_values = np.linspace(x_range[0], x_range[1], num_points)
param_values = self.model.calculate_all_parameters(x_values)
plt.figure(figsize=(14, 8))
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
for param_name, y_values in param_values.items():
plt.plot(x_values, y_values, label=param_name, linewidth=2)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
plt.grid(True, alpha=0.3)
plt.title("Все параметры модели")
plt.xlabel("x")
plt.ylabel("Значения параметров")
plt.legend()
plt.show()
def plot_main_formula(self, x_range: tuple = (-10, 10), num_points: int = 1000,
title: str = "Основная формула"):
"""График основной формулы"""
x_values = np.linspace(x_range[0], x_range[1], num_points)
y_values = self.model.calculate_main_formula(x_values)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
plt.figure(figsize=(10, 6))
plt.plot(x_values, y_values, 'r-', linewidth=2, label='Основная формула')
plt.grid(True, alpha=0.3)
plt.title(title)
plt.xlabel("x")
plt.ylabel("f(x)")
plt.legend()
plt.show()
def plot_dependency_graph(self):
"""Визуализация графа зависимостей"""
plt.figure(figsize=(12, 8))
pos = nx.spring_layout(self.model.dependency_graph, k=2, iterations=50)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
nx.draw(self.model.dependency_graph, pos,
with_labels=True, node_color='lightblue',
node_size=2000, font_size=10, font_weight='bold',
arrows=True, arrowsize=20, edge_color='gray')
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
plt.title("Граф зависимостей параметров")
plt.show()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Пример использования и заготовки функций
def create_example_model():
"""Создание примера модели для демонстрации"""
model = FormulaModel()
# Независимые параметры
param_a = Parameter(
name="A",
formula=lambda x: np.sin(x) + 2,
description="Синусоидальная функция",
units="м/с"
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
# Зависимый параметр (зависит от A)
param_b = Parameter(
name="B",
formula=lambda x, a: np.cos(x) * a,
dependencies=["A"],
description="Функция, зависящая от A",
units="м/с²"
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
# Параметр, зависящий от B
param_c = Parameter(
name="C",
formula=lambda x, b: np.exp(-x/10) * b,
dependencies=["B"],
description="Экспоненциальная функция от B",
units="Н"
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
# Параметр, зависящий от A и C
param_d = Parameter(
name="D",
formula=lambda x, a, c: (a**2 + c) / (1 + x**2),
dependencies=["A", "C"],
description="Комбинированная функция",
units="Дж"
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
# Независимый параметр
param_e = Parameter(
name="E",
formula=lambda x: np.log(1 + np.abs(x)),
description="Логарифмическая функция",
units="К"
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
# Добавление параметров в модель
for param in [param_a, param_b, param_c, param_d, param_e]:
model.add_parameter(param)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Основная формула, использующая несколько параметров
model.set_main_formula(
formula=lambda x, a, c, e: a * c + e**2,
dependencies=["A", "C", "E"]
2026-02-18 08:37:45 +00:00
)
2026-02-18 08:50:20 +00:00
return model
# Утилитарные функции
def analyze_model_complexity(model: FormulaModel):
"""Анализ сложности модели"""
print("=== Анализ модели ===")
print(f"Количество параметров: {len(model.parameters)}")
# Анализ зависимостей
max_depth = 0
for param_name in model.parameters:
try:
depth = nx.shortest_path_length(model.dependency_graph, param_name)
max_depth = max(max_depth, max(depth.values()) if depth else 0)
except:
pass
print(f"Максимальная глубина зависимостей: {max_depth}")
print(f"Порядок вычисления: {model.get_calculation_order()}")
return max_depth
def benchmark_model(model: FormulaModel, x_range: tuple = (-10, 10),
num_points: int = 10000):
"""Бенчмарк производительности модели"""
import time
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
x_values = np.linspace(x_range[0], x_range[1], num_points)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
start_time = time.time()
param_values = model.calculate_all_parameters(x_values)
end_time = time.time()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
print(f"Время вычисления всех параметров: {end_time - start_time:.4f} сек")
print(f"Точек данных: {num_points}")
print(f"Скорость: {num_points / (end_time - start_time):.0f} точек/сек")
# Основная функция для демонстрации
def main():
"""Основная функция для демонстрации работы скрипта"""
# Создание модели
model = create_example_model()
plotter = Plotter(model)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Анализ модели
analyze_model_complexity(model)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Построение графиков
plotter.plot_dependency_graph()
plotter.plot_all_parameters()
plotter.plot_main_formula()
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Графики отдельных параметров
for param_name in ["A", "B", "C"]:
plotter.plot_parameter(param_name)
2026-02-18 08:37:45 +00:00
2026-02-18 08:50:20 +00:00
# Бенчмарк
benchmark_model(model)
2026-02-18 08:37:45 +00:00
if __name__ == "__main__":
main()