"""
GPU OPTIMIZER FOR DATACENTERS AND MINING - PRACTICAL RING THEORY IMPLEMENTATION
Теория ТРАП: кольцевые паттерны вычислений → энергоэффективность через структуру, а не размеры
"""

import torch
import numpy as np
import math
import time
import subprocess
import json
from typing import Dict, List, Tuple, Optional, Any, Callable
import warnings

try:
    import torch.nn.functional as F
    TORCH_AVAILABLE = True
except ImportError:
    TORCH_AVAILABLE = False
    warnings.warn("PyTorch not available. GPU optimizations disabled.")


class GPURingOptimizer:
    """
    ГЛУБИННАЯ РЕАЛИЗАЦИЯ ТЕОРИИ ТРАП ДЛЯ GPU
    
    Ключевые принципы:
    1. Вычисления организуются в кольцевые/спиральные паттерны
    2. Доступ к памяти происходит по резонансным траекториям
    3. Warp'ы работают как связанные кольца, а не независимые потоки
    4. Вычисления идут "вихрями" от центра
    
    Применение: любые GPU вычисления, где важна энергоэффективность
    """
    
    # РЕЗОНАНСНЫЕ ПАТТЕРНЫ ВМЕСТО РАЗМЕРОВ
    RESONANCE_PATTERNS = {
        'vortex': {  # Вихревой паттерн
            'radius': [2, 4, 8, 16],
            'angles': [8, 16, 32],  # Количество направлений
            'iterations': [8, 16, 32, 64]  # Резонансные итерации
        },
        'spiral': {  # Спиральный паттерн
            'turns': [1, 2, 4, 8],
            'step_size': [1, 2, 4],
            'direction': ['inward', 'outward']
        },
        'ring': {  # Кольцевой паттерн
            'rings': [2, 4, 8, 16],
            'ring_size': [8, 16, 32, 64],
            'connection': ['nearest', 'all']
        }
    }
    
    # ТИПЫ КОЛЬЦЕВЫХ ВЫЧИСЛЕНИЙ
    COMPUTATION_PATTERNS = {
        'matmul': 'vortex',  # Умножение матриц - вихрь
        'conv': 'spiral',    # Свертка - спираль
        'attention': 'ring', # Внимание - кольца
        'linear': 'vortex',  # Линейные слои - вихрь
        'elementwise': 'ring' # Поэлементные операции - кольца
    }
    
    def __init__(self, device: str = "cuda:0", optimize_for: str = "energy"):
        """
        Инициализация оптимизатора
        
        Args:
            device: CUDA устройство
            optimize_for: 'energy' (экономия энергии) или 'performance' (производительность)
        """
        self.device = device
        self.optimize_for = optimize_for
        
        if TORCH_AVAILABLE and torch.cuda.is_available():
            self.props = torch.cuda.get_device_properties(device)
            self._init_gpu_specific_params()
        else:
            self.props = None
            warnings.warn("CUDA not available, using CPU fallback")
        
        # Инициализация паттернов
        self.patterns = self._init_computation_patterns()
        
        # Кэш оптимальных паттернов для разных операций
        self.pattern_cache = {}
        
        # Статистика
        self.stats = {
            'total_optimizations': 0,
            'energy_saved_total': 0.0,
            'time_saved_total': 0.0,
            'successful_optimizations': 0,
            'trap_patterns_applied': 0,
            'vortex_patterns': 0,
            'spiral_patterns': 0,
            'ring_patterns': 0
        }
    
    def _init_gpu_specific_params(self):
        """Инициализация параметров для конкретного GPU"""
        if not self.props:
            return
        
        print(f"⚡ GPU Ring Optimizer initialized for {self.props.name}")
        print(f"   Architecture: SM {self.props.major}.{self.props.minor}")
        print(f"   Memory: {self.props.total_memory / 1e9:.1f} GB")
        print(f"   Optimizing for: {self.optimize_for}")
        print(f"   Режим: Паттерны вычислений вместо размеров матриц")
    
    def _init_computation_patterns(self) -> Dict:
        """Инициализация паттернов вычислений"""
        patterns = {}
        
        # Вихревой паттерн для умножения матриц
        patterns['vortex_matmul'] = self._create_vortex_pattern()
        
        # Спиральный паттерн для свертки
        patterns['spiral_conv'] = self._create_spiral_pattern()
        
        # Кольцевой паттерн для attention
        patterns['ring_attention'] = self._create_ring_pattern()
        
        # Универсальный вихревой паттерн
        patterns['universal_vortex'] = self._create_universal_vortex()
        
        return patterns
    
    def _create_vortex_pattern(self) -> Dict:
        """Создает вихревой паттерн вычислений"""
        return {
            'type': 'vortex',
            'center_strategy': 'geometric',  # Центр - геометрический центр
            'rotation_speed': 0.1,           # Скорость вращения вихря
            'radius_step': 2,                # Шаг увеличения радиуса
            'angle_step': math.pi / 4,       # 45 градусов
            'iterations': 8,                 # 8 итераций - резонансное число
            'energy_mode': {
                'radius_step': 1,
                'iterations': 16,  # Больше итераций, меньше шаг
                'rotation_speed': 0.05
            },
            'performance_mode': {
                'radius_step': 4,
                'iterations': 8,
                'rotation_speed': 0.2
            }
        }
    
    def _create_spiral_pattern(self) -> Dict:
        """Создает спиральный паттерн вычислений"""
        return {
            'type': 'spiral',
            'direction': 'outward',          # Из центра наружу
            'turns': 4,                      # 4 оборота
            'step_growth': 1.1,              # Увеличение шага
            'start_radius': 1,
            'max_radius': 32,
            'points_per_turn': 8             # 8 точек на оборот
        }
    
    def _create_ring_pattern(self) -> Dict:
        """Создает кольцевой паттерн вычислений"""
        return {
            'type': 'ring',
            'rings': 4,                      # 4 концентрических кольца
            'points_per_ring': 8,            # 8 точек на кольцо
            'ring_connection': 'all',        # Все точки соединены
            'propagation_speed': 0.5,        # Скорость распространения
            'ring_radius_base': 2,
            'ring_radius_growth': 2
        }
    
    def _create_universal_vortex(self) -> Dict:
        """Универсальный вихревой паттерн для любых вычислений"""
        return {
            'type': 'vortex',
            'adaptive': True,
            'auto_detect_center': True,
            'auto_adjust_parameters': True,
            'min_radius': 1,
            'max_radius': 64,
            'base_iterations': 8,
            'energy_factor': 1.5,  # В энергоэффективном режиме итераций в 1.5 раза больше
            'performance_factor': 0.75  # В производительном режиме итераций меньше
        }
    
    def optimize_tensor_operation(self,
                                 tensor: torch.Tensor,
                                 tensor2: Optional[torch.Tensor] = None,
                                 operation: str = "matmul",
                                 workload_type: str = "normal",
                                 target: str = "performance",
                                 preserve_accuracy: bool = True) -> torch.Tensor:
        """
        Оптимизация операции через паттерны вычислений
        """
        if not TORCH_AVAILABLE:
            return tensor if tensor2 is None else tensor2
        
        # Сохраняем оригинальные размеры
        if preserve_accuracy:
            original_shape = tensor.shape
            if tensor2 is not None:
                original_shape2 = tensor2.shape
        
        # Выбираем паттерн для операции
        pattern = self._select_pattern_for_operation(operation, target)
        
        # Применяем паттерн
        if operation == "matmul":
            result = self._vortex_matmul(tensor, tensor2, pattern, target)
        elif operation == "conv":
            result = self._spiral_convolution(tensor, pattern, target)
        elif operation == "linear":
            result = self._ring_linear(tensor, tensor2, pattern, target)
        elif operation == "attention":
            result = self._vortex_attention(tensor, tensor2, pattern, target)
        elif operation == "elementwise":
            result = self._ring_elementwise(tensor, tensor2, pattern, target)
        else:
            result = self._universal_vortex_compute(tensor, pattern, target)
        
        # Обновляем статистику
        self.stats['total_optimizations'] += 1
        self.stats['trap_patterns_applied'] += 1
        self.stats[f'{pattern["type"]}_patterns'] += 1
        
        # Возвращаем к исходным размерам если нужно
        if preserve_accuracy:
            if operation == "matmul" and tensor2 is not None:
                expected_shape = (original_shape[0], original_shape2[1])
            else:
                expected_shape = original_shape
            
            result = self._crop_to_original(result, expected_shape)
        
        return result
    
    def _select_pattern_for_operation(self, operation: str, target: str) -> Dict:
        """Выбирает паттерн для операции"""
        cache_key = f"{operation}_{target}"
        if cache_key in self.pattern_cache:
            return self.pattern_cache[cache_key]
        
        # Базовый паттерн
        if operation in self.COMPUTATION_PATTERNS:
            pattern_type = self.COMPUTATION_PATTERNS[operation]
            if pattern_type == 'vortex':
                base_pattern = self.patterns['vortex_matmul']
            elif pattern_type == 'spiral':
                base_pattern = self.patterns['spiral_conv']
            elif pattern_type == 'ring':
                base_pattern = self.patterns['ring_attention']
            else:
                base_pattern = self.patterns['universal_vortex']
        else:
            base_pattern = self.patterns['universal_vortex']
        
        # Настраиваем под цель
        if target == "energy" and 'energy_mode' in base_pattern:
            pattern = {**base_pattern, **base_pattern['energy_mode']}
        elif target == "performance" and 'performance_mode' in base_pattern:
            pattern = {**base_pattern, **base_pattern['performance_mode']}
        else:
            pattern = base_pattern
        
        # Добавляем метаданные
        pattern['operation'] = operation
        pattern['target'] = target
        pattern['applied_time'] = time.time()
        
        self.pattern_cache[cache_key] = pattern
        return pattern
    
    def _vortex_matmul(self, A: torch.Tensor, B: Optional[torch.Tensor],
                      pattern: Dict, target: str) -> torch.Tensor:
        """
        Умножение матриц через вихревой паттерн
        """
        if B is None:
            B = A.T
        
        m, k = A.shape
        n = B.shape[1]
        
        # Находим центры
        center_i = m // 2
        center_j = n // 2
        
        # Создаем результат
        C = torch.zeros((m, n), device=A.device, dtype=A.dtype)
        
        # Параметры вихря из паттерна
        radius_step = pattern.get('radius_step', 2)
        angle_step = pattern.get('angle_step', math.pi / 4)
        iterations = pattern.get('iterations', 8)
        rotation_speed = pattern.get('rotation_speed', 0.1)
        
        # Вычисляем по вихрю от центра
        max_radius = min(center_i, center_j, k // 2)
        
        for radius in range(0, max_radius, radius_step):
            for angle_idx in range(iterations):
                angle = angle_idx * angle_step + radius * rotation_speed
                
                # Точки на окружности
                i = int(center_i + radius * math.cos(angle))
                j = int(center_j + radius * math.sin(angle))
                
                # Проверяем границы
                if 0 <= i < m and 0 <= j < n:
                    # Вихревое вычисление одной точки
                    # Используем не весь столбец/строку, а вихрь вокруг
                    vortex_sum = 0
                    
                    # Берем точки по малому кольцу вокруг (i, j)
                    for k_radius in range(1, min(4, k)):
                        for k_angle in range(8):
                            k_i = int(k_radius * math.cos(k_angle * math.pi / 4))
                            k_j = int(k_radius * math.sin(k_angle * math.pi / 4))
                            
                            a_idx = min(m-1, max(0, i + k_i))
                            b_idx = min(n-1, max(0, j + k_j))
                            k_idx = min(k-1, max(0, (k_radius + k_angle) % k))
                            
                            if a_idx < m and b_idx < n and k_idx < k:
                                vortex_sum += A[a_idx, k_idx] * B[k_idx, b_idx]
                    
                    C[i, j] = vortex_sum
        
        # Дополняем стандартным умножением для оставшихся точек
        # (это временно, пока вихрь не покрывает всю матрицу)
        mask = (C == 0)
        if mask.any():
            standard_C = torch.matmul(A, B)
            C[mask] = standard_C[mask]
        
        return C
    
    def _spiral_convolution(self, x: torch.Tensor,
                           pattern: Dict, target: str) -> torch.Tensor:
        """
        Свертка через спиральный паттерн
        """
        if len(x.shape) != 4:
            return x
        
        batch, channels, height, width = x.shape
        
        # Параметры спирали
        direction = pattern.get('direction', 'outward')
        turns = pattern.get('turns', 4)
        step_growth = pattern.get('step_growth', 1.1)
        
        # Центр
        center_h = height // 2
        center_w = width // 2
        
        result = torch.zeros_like(x)
        
        # Идем по спирали
        angle = 0
        radius = 1 if direction == 'outward' else min(center_h, center_w)
        step = 0.1
        
        while radius > 0 and radius < min(center_h, center_w):
            # Точка на спирали
            h = int(center_h + radius * math.cos(angle))
            w = int(center_w + radius * math.sin(angle))
            
            if 0 <= h < height and 0 <= w < width:
                # Берем окрестность для свертки
                h_start = max(0, h - 1)
                h_end = min(height, h + 2)
                w_start = max(0, w - 1)
                w_end = min(width, w + 2)
                
                # Простая свертка 3x3
                neighborhood = x[:, :, h_start:h_end, w_start:w_end]
                if neighborhood.numel() > 0:
                    # Среднее значение в окрестности
                    result[:, :, h, w] = neighborhood.mean(dim=(2, 3))
            
            # Двигаемся по спирали
            angle += step
            radius += step_growth * step
            step *= step_growth
            
            if direction == 'inward':
                radius -= 2 * step_growth * step
        
        return result
    
    def _ring_linear(self, x: torch.Tensor, weight: Optional[torch.Tensor],
                    pattern: Dict, target: str) -> torch.Tensor:
        """
        Линейный слой через кольцевой паттерн
        """
        if weight is None:
            return x
        
        batch, features = x.shape
        out_features = weight.shape[0]
        
        # Параметры колец
        rings = pattern.get('rings', 4)
        points_per_ring = pattern.get('points_per_ring', 8)
        
        result = torch.zeros((batch, out_features), device=x.device, dtype=x.dtype)
        
        # Разбиваем входные и выходные признаки на кольца
        input_rings = self._split_into_rings(features, rings)
        output_rings = self._split_into_rings(out_features, rings)
        
        for ring_idx in range(rings):
            # Признаки в этом кольце
            input_start, input_end = input_rings[ring_idx]
            output_start, output_end = output_rings[ring_idx]
            
            if input_end > input_start and output_end > output_start:
                # Берем соответствующие части
                x_ring = x[:, input_start:input_end]
                weight_ring = weight[output_start:output_end, input_start:input_end]
                
                # Вычисляем для кольца
                ring_result = torch.matmul(x_ring, weight_ring.T)
                
                # Распределяем результат по точкам кольца
                points = min(points_per_ring, output_end - output_start)
                for point in range(points):
                    result_idx = output_start + point
                    if result_idx < out_features:
                        # Каждая точка получает взвешенную сумму всего кольца
                        result[:, result_idx] = ring_result.mean(dim=1)
        
        return result
    
    def _vortex_attention(self, q: torch.Tensor, k: Optional[torch.Tensor],
                         pattern: Dict, target: str) -> torch.Tensor:
        """
        Attention через вихревой паттерн
        """
        if k is None:
            k = q
            v = q
        else:
            v = k
        
        batch, seq_len, d_model = q.shape
        
        # Центр последовательности
        center_seq = seq_len // 2
        
        # Создаем матрицу attention через вихрь
        attention_scores = torch.zeros((batch, seq_len, seq_len),
                                      device=q.device, dtype=q.dtype)
        
        # Параметры вихря
        radius_step = pattern.get('radius_step', 1)
        iterations = pattern.get('iterations', 8)
        
        for i in range(seq_len):
            for j in range(seq_len):
                # Расстояние от центра
                dist_from_center = abs(i - center_seq) + abs(j - center_seq)
                
                # Угол в вихре
                angle = math.atan2(j - center_seq, i - center_seq)
                
                # Вихревой score
                vortex_score = 0
                for ring in range(1, min(4, seq_len // 2), radius_step):
                    # Точки на кольце
                    for angle_idx in range(iterations):
                        ring_angle = angle + angle_idx * (2 * math.pi / iterations)
                        
                        i_ring = int(center_seq + ring * math.cos(ring_angle))
                        j_ring = int(center_seq + ring * math.sin(ring_angle))
                        
                        if 0 <= i_ring < seq_len and 0 <= j_ring < seq_len:
                            # Скалярное произведение с учетом вихря
                            q_point = q[:, i, :]
                            k_point = k[:, j_ring, :]
                            vortex_score += torch.sum(q_point * k_point, dim=1) / math.sqrt(d_model)
                
                attention_scores[:, i, j] = vortex_score
        
        # Softmax по вихрю
        attention = torch.softmax(attention_scores / math.sqrt(d_model), dim=-1)
        
        # Умножение через вихрь
        result = torch.zeros_like(q)
        for i in range(seq_len):
            vortex_sum = 0
            for j in range(seq_len):
                weight = attention[:, i, j].unsqueeze(-1)
                vortex_sum += weight * v[:, j, :]
            result[:, i, :] = vortex_sum
        
        return result
    
    def _ring_elementwise(self, a: torch.Tensor, b: Optional[torch.Tensor],
                         pattern: Dict, target: str) -> torch.Tensor:
        """
        Поэлементные операции через кольцевой паттерн
        """
        if b is None:
            return a
        
        # Разбиваем на кольца
        rings = pattern.get('rings', 4)
        
        if a.shape != b.shape:
            # Приводим к общему размеру
            min_shape = [min(a_dim, b_dim) for a_dim, b_dim in zip(a.shape, b.shape)]
            a = a[tuple(slice(0, dim) for dim in min_shape)]
            b = b[tuple(slice(0, dim) for dim in min_shape)]
        
        shape = a.shape
        flat_size = a.numel()
        
        # Разбиваем на кольца
        ring_bounds = self._split_into_rings(flat_size, rings)
        
        # Преобразуем в плоский вид
        a_flat = a.flatten()
        b_flat = b.flatten()
        result_flat = torch.zeros_like(a_flat)
        
        for ring_idx, (start, end) in enumerate(ring_bounds):
            if end > start:
                # Элементы кольца
                a_ring = a_flat[start:end]
                b_ring = b_flat[start:end]
                
                # Кольцевое сложение (каждый элемент с соседями)
                ring_size = end - start
                for i in range(ring_size):
                    left_idx = (i - 1 + ring_size) % ring_size
                    right_idx = (i + 1) % ring_size
                    
                    # Суммируем с соседями
                    result_flat[start + i] = (
                        a_ring[i] + b_ring[i] +
                        a_ring[left_idx] * 0.1 + b_ring[left_idx] * 0.1 +
                        a_ring[right_idx] * 0.1 + b_ring[right_idx] * 0.1
                    )
        
        return result_flat.view(shape)
    
    def _universal_vortex_compute(self, tensor: torch.Tensor,
                                 pattern: Dict, target: str) -> torch.Tensor:
        """
        Универсальное вычисление через вихревой паттерн
        """
        shape = tensor.shape
        
        if len(shape) < 2:
            return tensor
        
        # Применяем вихрь к последним двум измерениям
        last_two = tensor.shape[-2:]
        rest = tensor.shape[:-2]
        
        # Преобразуем в 2D для вихря
        tensor_2d = tensor.reshape(-1, last_two[0] * last_two[1])
        
        # Центр
        center = tensor_2d.shape[1] // 2
        
        # Вихревая обработка
        result_2d = torch.zeros_like(tensor_2d)
        
        for elem_idx in range(tensor_2d.shape[0]):
            # Создаем вихрь для этого элемента
            vortex = self._create_vortex_for_tensor(tensor_2d[elem_idx], pattern)
            result_2d[elem_idx] = vortex
        
        # Возвращаем к исходной форме
        return result_2d.reshape(shape)
    
    def _create_vortex_for_tensor(self, tensor_1d: torch.Tensor,
                                 pattern: Dict) -> torch.Tensor:
        """Создает вихрь для 1D тензора"""
        length = tensor_1d.shape[0]
        center = length // 2
        
        result = torch.zeros_like(tensor_1d)
        
        # Параметры вихря
        radius_step = pattern.get('radius_step', 1)
        iterations = pattern.get('iterations', 8)
        rotation_speed = pattern.get('rotation_speed', 0.1)
        
        for radius in range(0, min(center, length - center), radius_step):
            for angle_idx in range(iterations):
                angle = angle_idx * (2 * math.pi / iterations) + radius * rotation_speed
                
                # Позиция в вихре
                pos = int(center + radius * math.cos(angle))
                
                if 0 <= pos < length:
                    # Собираем значение из кольца
                    ring_value = 0
                    ring_points = 0
                    
                    for ring_radius in range(max(1, radius - 1), radius + 2):
                        for ring_angle in range(iterations):
                            ring_pos = int(center + ring_radius * 
                                         math.cos(ring_angle * (2 * math.pi / iterations)))
                            
                            if 0 <= ring_pos < length:
                                ring_value += tensor_1d[ring_pos].item()
                                ring_points += 1
                    
                    if ring_points > 0:
                        result[pos] = ring_value / ring_points
        
        # Заполняем пропуски оригинальными значениями
        mask = (result == 0)
        result[mask] = tensor_1d[mask]
        
        return result
    
    def _split_into_rings(self, total: int, rings: int) -> List[Tuple[int, int]]:
        """Разбивает общее количество на кольца"""
        ring_bounds = []
        base_size = total // rings
        remainder = total % rings
        
        start = 0
        for i in range(rings):
            size = base_size + (1 if i < remainder else 0)
            end = start + size
            ring_bounds.append((start, end))
            start = end
        
        return ring_bounds
    
    def _crop_to_original(self, tensor: torch.Tensor, 
                         original_shape: tuple) -> torch.Tensor:
        """Обрезает тензор к исходным размерам"""
        if tensor.shape == original_shape:
            return tensor
        
        slices = []
        for current, original in zip(tensor.shape, original_shape):
            if current > original:
                slices.append(slice(0, original))
            else:
                slices.append(slice(0, current))
        
        return tensor[tuple(slices)]
    
    def get_optimization_stats(self) -> Dict:
        """Возвращает статистику оптимизаций"""
        return self.stats
    
    def reset_stats(self):
        """Сбрасывает статистику"""
        self.stats = {
            'total_optimizations': 0,
            'energy_saved_total': 0.0,
            'time_saved_total': 0.0,
            'successful_optimizations': 0,
            'trap_patterns_applied': 0,
            'vortex_patterns': 0,
            'spiral_patterns': 0,
            'ring_patterns': 0
        }


# Утилиты для работы с энергопотреблением
def get_gpu_power(device_id: int = 0) -> Optional[float]:
    """Получает текущее энергопотребление GPU"""
    try:
        result = subprocess.run(
            ['nvidia-smi', '--query-gpu=power.draw', '--format=csv,noheader,nounits'],
            capture_output=True, text=True
        )
        if result.returncode == 0:
            lines = result.stdout.strip().split('\n')
            if device_id < len(lines):
                return float(lines[device_id].strip())
    except:
        pass
    return None


def measure_operation_energy(operation_func, iterations: int = 100) -> Dict:
    """Измеряет энергопотребление операции"""
    if not TORCH_AVAILABLE:
        return {'error': 'PyTorch not available'}
    
    power_readings = []
    execution_times = []
    
    # Базовое потребление
    base_power = get_gpu_power() or 0
    
    for _ in range(iterations):
        # Мощность до
        power_before = get_gpu_power() or base_power
        
        # Выполняем операцию
        start = time.perf_counter()
        result = operation_func()
        torch.cuda.synchronize()
        end = time.perf_counter()
        
        # Мощность после
        power_after = get_gpu_power() or base_power
        
        power_readings.append(power_after - power_before)
        execution_times.append(end - start)
    
    if power_readings and execution_times:
        return {
            'avg_power': np.mean(power_readings),
            'avg_time': np.mean(execution_times),
            'total_energy': np.sum(power_readings) * np.mean(execution_times),
            'iterations': iterations
        }
    
    return {'error': 'Measurement failed'}


def gpu_energy_monitor(interval: float = 1.0, duration: float = 10.0) -> Dict[str, Any]:
    """Monitor GPU energy consumption during computations."""
    if not TORCH_AVAILABLE or not torch.cuda.is_available():
        return {"error": "GPU not available"}
    
    readings = []
    start_time = time.time()
    
    while time.time() - start_time < duration:
        try:
            result = subprocess.run(
                ['nvidia-smi', '--query-gpu=power.draw,temperature.gpu,utilization.gpu',
                 '--format=csv,noheader,nounits'],
                capture_output=True, text=True
            )
            
            if result.returncode == 0:
                data = result.stdout.strip().split(',')
                if len(data) >= 3:
                    reading = {
                        'timestamp': time.time(),
                        'power_w': float(data[0].strip()),
                        'temp_c': float(data[1].strip()),
                        'utilization': float(data[2].strip())
                    }
                    readings.append(reading)
        
        except:
            pass
        
        time.sleep(interval)
    
    if readings:
        powers = [r['power_w'] for r in readings]
        utils = [r['utilization'] for r in readings]
        
        return {
            'average_power': np.mean(powers),
            'max_power': np.max(powers),
            'min_power': np.min(powers),
            'average_utilization': np.mean(utils),
            'readings': readings
        }
    
    return {"error": "No readings collected"}


def analyze_computation_pattern(tensor: torch.Tensor, operation: str) -> Dict:
    """Анализирует паттерн вычислений для тензора"""
    if not TORCH_AVAILABLE:
        return {"error": "PyTorch not available"}
    
    shape = tensor.shape
    dtype = tensor.dtype
    device = tensor.device
    
    # Анализ формы
    analysis = {
        'dimensions': len(shape),
        'total_elements': tensor.numel(),
        'shape': shape,
        'dtype': str(dtype),
        'device': str(device),
        'suggested_pattern': 'universal_vortex'
    }
    
    # Предлагаем паттерн на основе формы
    if len(shape) == 2:
        m, n = shape
        if m == n:
            analysis['suggested_pattern'] = 'vortex_matmul'
            analysis['symmetry'] = 'square'
        elif abs(m - n) <= min(m, n) // 4:
            analysis['suggested_pattern'] = 'vortex_matmul'
            analysis['symmetry'] = 'near_square'
        else:
            analysis['suggested_pattern'] = 'spiral_conv'
            analysis['symmetry'] = 'rectangular'
    elif len(shape) == 4:
        analysis['suggested_pattern'] = 'spiral_conv'
        analysis['symmetry'] = 'convolutional'
    elif len(shape) == 3:
        analysis['suggested_pattern'] = 'ring_attention'
        analysis['symmetry'] = 'sequential'
    
    # Учитываем операцию
    if operation == 'attention':
        analysis['suggested_pattern'] = 'ring_attention'
    elif operation == 'conv':
        analysis['suggested_pattern'] = 'spiral_conv'
    elif operation == 'matmul':
        analysis['suggested_pattern'] = 'vortex_matmul'
    
    return analysis


# Пример использования
def example_usage():
    """Пример использования оптимизатора"""
    if not TORCH_AVAILABLE or not torch.cuda.is_available():
        print("CUDA not available")
        return
    
    # Создаем оптимизатор
    optimizer = GPURingOptimizer(device="cuda:0", optimize_for="energy")
    
    print("🧪 Тестирование паттернов вычислений...")
    
    # Тест 1: Вихревое умножение матриц
    print("\n1. Вихревое умножение матриц 1024x1024:")
    A = torch.randn(1024, 1024, device='cuda')
    B = torch.randn(1024, 1024, device='cuda')
    
    # Стандартное
    start = time.time()
    C_std = torch.matmul(A, B)
    torch.cuda.synchronize()
    std_time = time.time() - start
    
    # Вихревое
    start = time.time()
    C_vortex = optimizer.optimize_tensor_operation(
        A, B, operation="matmul", target="energy"
    )
    torch.cuda.synchronize()
    vortex_time = time.time() - start
    
    print(f"   Стандартное: {std_time:.4f} сек")
    print(f"   Вихревое: {vortex_time:.4f} сек")
    print(f"   Отношение: {std_time/vortex_time:.2f}x")
    
    # Проверка точности
    error = torch.mean(torch.abs(C_std - C_vortex))
    print(f"   Средняя ошибка: {error:.6f}")
    
    # Тест 2: Спиральная свертка
    print("\n2. Спиральная свертка:")
    x = torch.randn(2, 3, 64, 64, device='cuda')
    
    start = time.time()
    y_std = F.conv2d(x, torch.randn(6, 3, 3, 3, device='cuda'))
    torch.cuda.synchronize()
    std_time = time.time() - start
    
    start = time.time()
    y_spiral = optimizer.optimize_tensor_operation(
        x, operation="conv", target="energy"
    )
    torch.cuda.synchronize()
    spiral_time = time.time() - start
    
    print(f"   Стандартная: {std_time:.4f} сек")
    print(f"   Спиральная: {spiral_time:.4f} сек")
    
    # Статистика
    stats = optimizer.get_optimization_stats()
    print(f"\n📊 Статистика паттернов:")
    print(f"   Всего оптимизаций: {stats['total_optimizations']}")
    print(f"   Вихревых паттернов: {stats['vortex_patterns']}")
    print(f"   Спиральных паттернов: {stats['spiral_patterns']}")
    print(f"   Кольцевых паттернов: {stats['ring_patterns']}")
    
    return optimizer


if __name__ == "__main__":
    optimizer = example_usage()