""" USSU Algorithm Analyzer v4.0 - Core Engine (Flask Edition) Author: Ussu (github.com/issu321) Cyberpunk-themed core with profiling, graph structures, and ADA utilities. """ import time import tracemalloc import random import math import heapq from collections import defaultdict, deque from dataclasses import dataclass, field from typing import Dict, List, Set, Tuple, Optional, Callable, Any from functools import wraps class CyberCSS: """Inject custom cyberpunk CSS - kept for compatibility""" @staticmethod def inject(): pass # No-op in Flask edition class Colors: """ANSI colors for terminal fallback / reference""" CYAN = '#06b6d4' BRIGHT_CYAN = '#22d3ee' NEON_BLUE = '#38bdf8' VIOLET = '#8b5cf6' GREEN = '#10b981' YELLOW = '#f59e0b' RED = '#ef4444' MAGENTA = '#d946ef' SLATE = '#1e293b' DARK = '#0f172a' GRAY = '#94a3b8' WHITE = '#f8fafc' @dataclass class AlgorithmMetrics: """Standardized metrics container for every algorithm run""" algorithm: str time_complexity: str space_complexity: str execution_time_ms: float = 0.0 memory_used_kb: float = 0.0 comparisons: int = 0 swaps: int = 0 accesses: int = 0 recursions: int = 0 iterations: int = 0 found: bool = False index: int = -1 path: List[Any] = field(default_factory=list) distance: float = 0.0 extra: Dict[str, Any] = field(default_factory=dict) def profile_algorithm(func: Callable) -> Callable: """Decorator to profile execution time, memory, and operations""" @wraps(func) def wrapper(*args, **kwargs): # Reset counters if analyzer instance exists if args and hasattr(args[0], 'reset_counters'): args[0].reset_counters() tracemalloc.start() start_time = time.perf_counter() result = func(*args, **kwargs) end_time = time.perf_counter() current, peak = tracemalloc.get_traced_memory() tracemalloc.stop() exec_time = (end_time - start_time) * 1000 mem_kb = peak / 1024 # Attach metrics if result is dict or Metrics if isinstance(result, dict): result.setdefault('execution_time_ms', exec_time) result.setdefault('memory_used_kb', mem_kb) elif isinstance(result, AlgorithmMetrics): result.execution_time_ms = exec_time result.memory_used_kb = mem_kb return result return wrapper class Graph: """Advanced Graph data structure with multiple representations""" def __init__(self, directed: bool = False, weighted: bool = False): self.directed = directed self.weighted = weighted self.adjacency_list: Dict[int, List[Tuple[int, Optional[float]]]] = defaultdict(list) self.vertices: Set[int] = set() self.edges: List[Tuple[int, int, Optional[float]]] = [] self.edge_count = 0 def add_vertex(self, vertex: int): self.vertices.add(vertex) if vertex not in self.adjacency_list: self.adjacency_list[vertex] = [] def add_edge(self, u: int, v: int, weight: float = 1.0): self.add_vertex(u) self.add_vertex(v) self.adjacency_list[u].append((v, weight if self.weighted else None)) self.edges.append((u, v, weight if self.weighted else None)) self.edge_count += 1 if not self.directed: self.adjacency_list[v].append((u, weight if self.weighted else None)) def get_neighbors(self, vertex: int) -> List[Tuple[int, Optional[float]]]: return self.adjacency_list.get(vertex, []) def get_degree(self, vertex: int) -> int: if self.directed: out_deg = len(self.adjacency_list.get(vertex, [])) in_deg = sum(1 for v in self.vertices for x, _ in self.adjacency_list[v] if x == vertex) return in_deg + out_deg return len(self.adjacency_list.get(vertex, [])) def to_matrix(self) -> List[List[float]]: n = max(self.vertices) + 1 if self.vertices else 0 matrix = [[float('inf')] * n for _ in range(n)] for i in range(n): matrix[i][i] = 0 for u in self.vertices: for v, w in self.adjacency_list[u]: weight = w if w is not None else 1 matrix[u][v] = min(matrix[u][v], weight) return matrix @classmethod def from_random(cls, n: int, edge_prob: float = 0.3, directed: bool = False, weighted: bool = False, weight_range: Tuple[int, int] = (1, 10)): g = cls(directed=directed, weighted=weighted) for i in range(n): g.add_vertex(i) for i in range(n): for j in range(n): if i != j and random.random() < edge_prob: weight = random.randint(*weight_range) if weighted else 1 if not directed and j < i: continue g.add_edge(i, j, weight) return g @classmethod def from_edges(cls, edges_str: str, directed: bool = False, weighted: bool = False): """Parse edges from string like '0 1 5; 1 2 3; 2 0 2'""" g = cls(directed=directed, weighted=weighted) for line in edges_str.replace(';', '\n').split('\n'): line = line.strip() if not line: continue parts = line.split() if len(parts) >= 2: u, v = int(parts[0]), int(parts[1]) w = float(parts[2]) if len(parts) > 2 and weighted else None g.add_edge(u, v, w) return g def to_dict(self): """Serialize for JSON/JS graph visualization""" nodes = [{"id": v, "label": str(v)} for v in self.vertices] edge_list = [] seen = set() for u, v, w in self.edges: if not self.directed and (v, u) in seen: continue seen.add((u, v)) edge_list.append({ "from": u, "to": v, "label": str(w) if w is not None else "", "arrows": "to" if self.directed else "" }) return {"nodes": nodes, "edges": edge_list, "directed": self.directed, "weighted": self.weighted} class OperationCounter: """Mixin for algorithms that count operations""" def __init__(self): self.comparisons = 0 self.swaps = 0 self.accesses = 0 self.recursions = 0 self.iterations = 0 def reset_counters(self): self.comparisons = 0 self.swaps = 0 self.accesses = 0 self.recursions = 0 self.iterations = 0 def to_dict(self) -> Dict[str, int]: return { 'comparisons': self.comparisons, 'swaps': self.swaps, 'accesses': self.accesses, 'recursions': self.recursions, 'iterations': self.iterations, }