Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| """ | |
| ================================================================================ | |
| USSU'S ULTRA PRO MAX ALGORITHM ANALYZER v4.0 | |
| Flask Cyberpunk Edition — Interactive Web Deploy Ready | |
| Complete analysis of Graph Algorithms, Searching, Sorting, MST, Shortest Path, | |
| Dynamic Programming, Greedy, Backtracking, ADA Theory, Math Tools, | |
| Speed Benchmarking | Performance Profiling | Futuristic Glassmorphism UI | |
| Author: Ussu (github.com/issu321) | |
| Repo: https://github.com/issu321/Analysis-of-Algorithms | |
| Kali Linux Compatible | Python 3.13 Ready | Windows 11 Ready | |
| ================================================================================ | |
| """ | |
| import os | |
| import sys | |
| import json | |
| import random | |
| import math | |
| from flask import Flask, render_template, request, jsonify, send_file | |
| # Add project root to path | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| from utils.core import Graph, Colors | |
| from utils.viz import ( | |
| fig_to_base64, plot_graph_cyber, plot_sorting_step, plot_sorting_frames, | |
| plot_benchmark_bar, plot_benchmark_lines, plot_dp_table, | |
| plot_asymptotic_growth, plot_recursion_tree | |
| ) | |
| from algorithms.search import SearchingAlgorithms | |
| from algorithms.sort import SortingAlgorithms | |
| from algorithms.graph import GraphAlgorithms | |
| from algorithms.dp import DynamicProgramming | |
| from algorithms.greedy import GreedyAlgorithms | |
| from algorithms.backtrack import BacktrackingAlgorithms | |
| from algorithms.math_tools import MathTools | |
| from algorithms.ada import ADATools | |
| from algorithms.benchmark import BenchmarkSuite | |
| app = Flask(__name__) | |
| app.secret_key = "ussu-algorithm-analyzer-v4-flask-secret-key" | |
| # Jinja2 globals for template safety | |
| app.jinja_env.globals['float'] = float | |
| app.jinja_env.globals['inf'] = float('inf') | |
| app.jinja_env.globals['len'] = len | |
| app.jinja_env.globals['zip'] = zip | |
| # Custom Jinja2 filters | |
| def tojson_pretty(value): | |
| return json.dumps(value, indent=2, default=str) | |
| # ============================ HOME ============================ | |
| def home(): | |
| return render_template("home.html") | |
| # ============================ GRAPH ============================ | |
| def graph_page(): | |
| result = None | |
| graph_data = None | |
| img_data = None | |
| algo = request.form.get("algo", "bfs") | |
| if request.method == "POST": | |
| action = request.form.get("action", "") | |
| if action == "create": | |
| n = int(request.form.get("n", 5)) | |
| p = float(request.form.get("p", 0.3)) | |
| directed = request.form.get("directed") == "on" | |
| weighted = request.form.get("weighted") == "on" | |
| g = Graph.from_random(n, p, directed, weighted) | |
| graph_data = g.to_dict() | |
| result = {"message": f"Graph created: {len(g.vertices)}V {g.edge_count}E", "status": "ok"} | |
| elif action == "custom": | |
| edges_str = request.form.get("edges", "") | |
| directed = request.form.get("directed") == "on" | |
| weighted = request.form.get("weighted") == "on" | |
| try: | |
| g = Graph.from_edges(edges_str, directed, weighted) | |
| graph_data = g.to_dict() | |
| result = {"message": f"Custom graph: {len(g.vertices)}V {g.edge_count}E", "status": "ok"} | |
| # Debug: ensure graph_data has content | |
| if not graph_data.get("nodes"): | |
| result = {"message": "No valid edges parsed. Check format: u v [w] per line", "status": "warning"} | |
| graph_data = None | |
| except Exception as e: | |
| result = {"message": f"Error parsing edges: {str(e)}", "status": "error"} | |
| graph_data = None | |
| elif action == "run" and request.form.get("graph_json"): | |
| g_dict = json.loads(request.form.get("graph_json")) | |
| g = Graph(directed=g_dict.get("directed", False), weighted=g_dict.get("weighted", False)) | |
| for n in g_dict.get("nodes", []): | |
| g.add_vertex(n["id"]) | |
| for e in g_dict.get("edges", []): | |
| w = float(e["label"]) if e.get("label") and g.weighted else None | |
| g.add_edge(e["from"], e["to"], w if w else 1.0) | |
| ga = GraphAlgorithms() | |
| start = int(request.form.get("start", 0)) | |
| target = request.form.get("target", "") | |
| target = int(target) if target.strip() != "" else None | |
| if algo == "bfs": | |
| result = ga.bfs(g, start, target) | |
| elif algo == "dfs_iter": | |
| result = ga.dfs_iterative(g, start, target) | |
| elif algo == "dfs_rec": | |
| result = ga.dfs_recursive(g, start, target) | |
| elif algo == "dijkstra": | |
| result = ga.dijkstra(g, start, target) | |
| elif algo == "bellman_ford": | |
| result = ga.bellman_ford(g, start) | |
| elif algo == "floyd_warshall": | |
| result = ga.floyd_warshall(g) | |
| elif algo == "prim": | |
| result = ga.prim_mst(g) | |
| elif algo == "kruskal": | |
| result = ga.kruskal_mst(g) | |
| elif algo == "topological": | |
| result = ga.topological_sort(g) | |
| elif algo == "kosaraju": | |
| result = ga.kosaraju_scc(g) | |
| elif algo == "astar": | |
| result = ga.a_star(g, start, target if target else 0) | |
| elif algo == "longest_path_dag": | |
| result = ga.longest_path_dag(g, start) | |
| graph_data = g.to_dict() | |
| highlight_path = result.get("path", []) | |
| highlight_nodes = result.get("traversal", []) if not highlight_path else [] | |
| fig = plot_graph_cyber(g, highlight_path=highlight_path if highlight_path else None, | |
| highlight_nodes=highlight_nodes if highlight_nodes else None, | |
| title=f"{result.get('algorithm', 'Graph')} Result") | |
| img_data = fig_to_base64(fig) | |
| return render_template("graph.html", result=result, graph_data=graph_data, img_data=img_data, algo=algo) | |
| # ============================ SEARCH ============================ | |
| def search_page(): | |
| result = None | |
| compare_results = None | |
| if request.method == "POST": | |
| arr_str = request.form.get("arr", "1 3 5 7 9 11 13") | |
| arr = list(map(int, arr_str.split())) | |
| target = int(request.form.get("target", 7)) | |
| algo = request.form.get("algo", "binary") | |
| searcher = SearchingAlgorithms() | |
| if algo == "compare": | |
| compare_results = searcher.compare_all(arr, target) | |
| else: | |
| algo_map = { | |
| "linear": searcher.linear_search, | |
| "binary": searcher.binary_search_iterative, | |
| "binary_rec": searcher.binary_search_recursive, | |
| "jump": searcher.jump_search, | |
| "interpolation": searcher.interpolation_search, | |
| "exponential": searcher.exponential_search, | |
| "ternary": searcher.ternary_search, | |
| "fibonacci": searcher.fibonacci_search, | |
| } | |
| if algo in algo_map: | |
| result = algo_map[algo](arr, target) | |
| return render_template("search.html", result=result, compare_results=compare_results) | |
| # ============================ SORT ============================ | |
| def sort_page(): | |
| result = None | |
| compare_results = None | |
| step_images = None | |
| if request.method == "POST": | |
| arr_str = request.form.get("arr", "64 34 25 12 22 11 90") | |
| arr = list(map(int, arr_str.split())) | |
| algo = request.form.get("algo", "merge") | |
| capture = request.form.get("capture_steps") == "on" | |
| sorter = SortingAlgorithms(capture_steps=capture) | |
| if algo == "compare": | |
| compare_results = sorter.compare_all(arr) | |
| else: | |
| algo_map = { | |
| "bubble": sorter.bubble_sort, | |
| "selection": sorter.selection_sort, | |
| "insertion": sorter.insertion_sort, | |
| "merge": sorter.merge_sort, | |
| "quick": sorter.quick_sort, | |
| "heap": sorter.heap_sort, | |
| "shell": sorter.shell_sort, | |
| "cocktail": sorter.cocktail_shaker_sort, | |
| "comb": sorter.comb_sort, | |
| "counting": sorter.counting_sort, | |
| "radix": sorter.radix_sort, | |
| "bucket": lambda a: sorter.bucket_sort([float(x) for x in a]), | |
| "timsort": sorter.tim_sort, | |
| } | |
| if algo in algo_map: | |
| result = algo_map[algo](arr) | |
| if capture and result.get("steps"): | |
| step_images = plot_sorting_frames(result["steps"]) | |
| return render_template("sort.html", result=result, compare_results=compare_results, step_images=step_images) | |
| # ============================ DP ============================ | |
| def dp_page(): | |
| result = None | |
| dp_img = None | |
| if request.method == "POST": | |
| algo = request.form.get("algo", "knapsack") | |
| dp = DynamicProgramming() | |
| if algo == "knapsack": | |
| w = list(map(int, request.form.get("weights", "2 3 4 5").split())) | |
| v = list(map(int, request.form.get("values", "3 4 5 6").split())) | |
| cap = int(request.form.get("capacity", 5)) | |
| result = dp.knapsack_01(w, v, cap) | |
| if result.get("dp_table"): | |
| fig = plot_dp_table(result["dp_table"], "0/1 Knapsack DP Table", | |
| row_labels=[f"Item {i}" for i in range(len(w)+1)], | |
| col_labels=[str(i) for i in range(cap+1)]) | |
| dp_img = fig_to_base64(fig) | |
| elif algo == "unbounded_knapsack": | |
| w = list(map(int, request.form.get("weights", "2 3 4 5").split())) | |
| v = list(map(int, request.form.get("values", "3 4 5 6").split())) | |
| cap = int(request.form.get("capacity", 5)) | |
| result = dp.knapsack_unbounded(w, v, cap) | |
| elif algo == "lcs": | |
| s1 = request.form.get("s1", "AGGTAB") | |
| s2 = request.form.get("s2", "GXTXAYB") | |
| result = dp.lcs(s1, s2) | |
| if result.get("dp_table"): | |
| fig = plot_dp_table(result["dp_table"], "LCS DP Table", | |
| row_labels=[""] + list(s1), | |
| col_labels=[""] + list(s2)) | |
| dp_img = fig_to_base64(fig) | |
| elif algo == "edit_distance": | |
| s1 = request.form.get("s1", "kitten") | |
| s2 = request.form.get("s2", "sitting") | |
| result = dp.edit_distance(s1, s2) | |
| if result.get("dp_table"): | |
| fig = plot_dp_table(result["dp_table"], "Edit Distance DP Table", | |
| row_labels=[""] + list(s1), | |
| col_labels=[""] + list(s2)) | |
| dp_img = fig_to_base64(fig) | |
| elif algo == "matrix_chain": | |
| dims = list(map(int, request.form.get("dims", "10 30 5 60").split())) | |
| result = dp.matrix_chain_order(dims) | |
| if result.get("dp_table"): | |
| n = len(dims) - 1 | |
| fig = plot_dp_table(result["dp_table"], "Matrix Chain DP Table", | |
| row_labels=[f"A{i+1}" for i in range(n)], | |
| col_labels=[f"A{i+1}" for i in range(n)]) | |
| dp_img = fig_to_base64(fig) | |
| elif algo == "coin_change_min": | |
| coins = list(map(int, request.form.get("coins", "1 2 5").split())) | |
| amt = int(request.form.get("amount", 11)) | |
| result = dp.coin_change_min(coins, amt) | |
| elif algo == "coin_change_ways": | |
| coins = list(map(int, request.form.get("coins", "1 2 5").split())) | |
| amt = int(request.form.get("amount", 5)) | |
| result = dp.coin_change_ways(coins, amt) | |
| elif algo == "lis": | |
| arr = list(map(int, request.form.get("arr", "10 9 2 5 3 7 101 18").split())) | |
| result = dp.lis(arr) | |
| return render_template("dp.html", result=result, dp_img=dp_img) | |
| # ============================ GREEDY ============================ | |
| def greedy_page(): | |
| result = None | |
| if request.method == "POST": | |
| algo = request.form.get("algo", "activity") | |
| greedy = GreedyAlgorithms() | |
| if algo == "activity": | |
| n = int(request.form.get("n", 4)) | |
| acts = [] | |
| for i in range(n): | |
| s = int(request.form.get(f"start_{i}", 0)) | |
| f = int(request.form.get(f"finish_{i}", 0)) | |
| acts.append((s, f, f"A{i+1}")) | |
| result = greedy.activity_selection(acts) | |
| elif algo == "fractional_knapsack": | |
| w = list(map(int, request.form.get("weights", "10 20 30").split())) | |
| v = list(map(int, request.form.get("values", "60 100 120").split())) | |
| cap = int(request.form.get("capacity", 50)) | |
| result = greedy.fractional_knapsack(w, v, cap) | |
| elif algo == "huffman": | |
| text = request.form.get("text", "hello world") | |
| from collections import Counter | |
| result = greedy.huffman_coding(dict(Counter(text))) | |
| elif algo == "job_sequencing": | |
| n = int(request.form.get("n", 3)) | |
| jobs = [] | |
| for i in range(n): | |
| d = int(request.form.get(f"deadline_{i}", 0)) | |
| p = int(request.form.get(f"profit_{i}", 0)) | |
| jobs.append((f"J{i+1}", d, p)) | |
| result = greedy.job_sequencing(jobs) | |
| elif algo == "min_coins": | |
| coins = list(map(int, request.form.get("coins", "1 5 10 25").split())) | |
| amount = int(request.form.get("amount", 30)) | |
| result = greedy.minimum_coins_greedy(coins, amount) | |
| return render_template("greedy.html", result=result) | |
| # ============================ BACKTRACK ============================ | |
| def backtrack_page(): | |
| result = None | |
| if request.method == "POST": | |
| algo = request.form.get("algo", "n_queens") | |
| bt = BacktrackingAlgorithms() | |
| if algo == "n_queens": | |
| n = int(request.form.get("n", 8)) | |
| result = bt.n_queens(n) | |
| elif algo == "sudoku": | |
| grid = [] | |
| for i in range(9): | |
| row = list(map(int, request.form.get(f"row_{i}", "0 0 0 0 0 0 0 0 0").split())) | |
| grid.append(row) | |
| result = bt.sudoku_solver(grid) | |
| elif algo == "subset_sum": | |
| arr = list(map(int, request.form.get("arr", "3 34 4 12 5 2").split())) | |
| target = int(request.form.get("target", 9)) | |
| result = bt.subset_sum(arr, target) | |
| elif algo == "graph_coloring": | |
| n = int(request.form.get("n", 4)) | |
| m = int(request.form.get("m", 3)) | |
| adj = [] | |
| for i in range(n): | |
| row = list(map(int, request.form.get(f"adj_row_{i}", "0 0 0 0").split())) | |
| adj.append(row) | |
| result = bt.graph_coloring(adj, m) | |
| elif algo == "hamiltonian": | |
| n = int(request.form.get("n", 4)) | |
| start = int(request.form.get("start", 0)) | |
| adj = [] | |
| for i in range(n): | |
| row = list(map(int, request.form.get(f"ham_row_{i}", "0 0 0 0").split())) | |
| adj.append(row) | |
| result = bt.hamiltonian_cycle(adj, start) | |
| return render_template("backtrack.html", result=result) | |
| # ============================ MATH ============================ | |
| def math_page(): | |
| result = None | |
| if request.method == "POST": | |
| algo = request.form.get("algo", "gcd") | |
| mt = MathTools() | |
| if algo == "factorial": | |
| n = int(request.form.get("n", 5)) | |
| result = mt.factorial(n) | |
| elif algo == "fibonacci": | |
| n = int(request.form.get("n", 10)) | |
| method = request.form.get("method", "iterative") | |
| result = mt.fibonacci(n, method) | |
| elif algo == "gcd": | |
| a = int(request.form.get("a", 48)) | |
| b = int(request.form.get("b", 18)) | |
| result = mt.gcd(a, b) | |
| elif algo == "extended_gcd": | |
| a = int(request.form.get("a", 48)) | |
| b = int(request.form.get("b", 18)) | |
| result = mt.extended_gcd(a, b) | |
| elif algo == "fast_power": | |
| b = float(request.form.get("base", 2)) | |
| e = int(request.form.get("exp", 10)) | |
| result = mt.fast_exponentiation(b, e) | |
| elif algo == "modular_power": | |
| base = int(request.form.get("base", 2)) | |
| exp = int(request.form.get("exp", 10)) | |
| mod = int(request.form.get("mod", 1000)) | |
| result = mt.modular_exponentiation(base, exp, mod) | |
| elif algo == "is_prime": | |
| n = int(request.form.get("n", 97)) | |
| result = mt.is_prime(n) | |
| elif algo == "sieve": | |
| n = int(request.form.get("n", 50)) | |
| result = mt.sieve_eratosthenes(n) | |
| elif algo == "matrix_multiply": | |
| A = [[float(request.form.get(f"a_{i}_{j}", 0)) for j in range(2)] for i in range(2)] | |
| B = [[float(request.form.get(f"b_{i}_{j}", 0)) for j in range(2)] for i in range(2)] | |
| result = mt.matrix_multiply(A, B) | |
| elif algo == "tower_hanoi": | |
| n = int(request.form.get("n", 3)) | |
| result = mt.tower_of_hanoi(n) | |
| elif algo == "permutations": | |
| arr = request.form.get("arr", "1 2 3").split() | |
| result = mt.generate_permutations(arr) | |
| return render_template("math.html", result=result) | |
| # ============================ ADA ============================ | |
| def ada_page(): | |
| result = None | |
| ref_data = None | |
| if request.method == "POST": | |
| algo = request.form.get("algo", "master") | |
| ada = ADATools() | |
| if algo == "master": | |
| a = float(request.form.get("a", 2)) | |
| b = float(request.form.get("b", 2)) | |
| f = request.form.get("f", "n") | |
| result = ada.master_theorem(a, b, f) | |
| elif algo == "recursion_tree": | |
| a = float(request.form.get("a", 2)) | |
| b = float(request.form.get("b", 2)) | |
| n = float(request.form.get("n", 16)) | |
| f_str = request.form.get("f_func", "n") | |
| # Parse simple f(n) | |
| if f_str == "n": | |
| f_func = lambda x: x | |
| elif f_str == "n^2": | |
| f_func = lambda x: x**2 | |
| elif f_str == "1": | |
| f_func = lambda x: 1 | |
| elif f_str == "n*log(n)": | |
| f_func = lambda x: x * math.log(x) if x > 0 else 0 | |
| else: | |
| f_func = lambda x: x | |
| result = ada.recursion_tree_cost(a, b, f_func, n) | |
| elif algo == "amortized_array": | |
| n = int(request.form.get("n", 20)) | |
| result = ada.amortized_dynamic_array(n) | |
| elif algo == "amortized_counter": | |
| n_bits = int(request.form.get("n_bits", 8)) | |
| increments = int(request.form.get("increments", 20)) | |
| result = ada.amortized_binary_counter(n_bits, increments) | |
| elif algo == "hiring": | |
| n = int(request.form.get("n", 10)) | |
| result = ada.hiring_problem(n) | |
| elif algo == "randomized_quicksort": | |
| n = int(request.form.get("n", 100)) | |
| result = ada.randomized_quicksort_analysis(n) | |
| else: | |
| ada = ADATools() | |
| ref_data = { | |
| "big_o": ada.big_o_reference(), | |
| "definitions": ada.asymptotic_definitions(), | |
| "np": ada.np_completeness_reference(), | |
| "paradigms": ada.paradigm_comparison(), | |
| } | |
| return render_template("ada.html", result=result, ref_data=ref_data) | |
| # ============================ BENCHMARK ============================ | |
| def benchmark_page(): | |
| result = None | |
| chart_img = None | |
| if request.method == "POST": | |
| suite = request.form.get("suite", "search") | |
| bench = BenchmarkSuite() | |
| if suite == "search": | |
| sizes = [100, 1000, 5000, 10000] | |
| result = bench.benchmark_search(sizes) | |
| # Transform for line chart | |
| chart_data = {} | |
| for r in result: | |
| for algo, t in r["times"].items(): | |
| chart_data.setdefault(algo, []).append({"size": r["size"], "time_ms": t}) | |
| fig = plot_benchmark_lines(chart_data, title="Search Benchmark Scaling") | |
| chart_img = fig_to_base64(fig) | |
| elif suite == "sort": | |
| sizes = [100, 500, 1000, 2000] | |
| result = bench.benchmark_sort(sizes) | |
| chart_data = {} | |
| for r in result: | |
| for algo, t in r["times"].items(): | |
| chart_data.setdefault(algo, []).append({"size": r["size"], "time_ms": t}) | |
| fig = plot_benchmark_lines(chart_data, title="Sort Benchmark Scaling") | |
| chart_img = fig_to_base64(fig) | |
| elif suite == "graph": | |
| sizes = [10, 20, 50, 100] | |
| result = bench.benchmark_graph(sizes) | |
| chart_data = {} | |
| for r in result: | |
| for algo in ["bfs", "dfs", "dijkstra"]: | |
| chart_data.setdefault(algo.upper(), []).append({"size": r["size"], "time_ms": r[algo]}) | |
| fig = plot_benchmark_lines(chart_data, title="Graph Benchmark Scaling") | |
| chart_img = fig_to_base64(fig) | |
| elif suite == "dp": | |
| sizes = [5, 10, 15, 20] | |
| result = bench.benchmark_dp(sizes) | |
| chart_data = {} | |
| for r in result: | |
| for algo in ["knapsack", "lcs"]: | |
| chart_data.setdefault(algo.upper(), []).append({"size": r["size"], "time_ms": r[algo]}) | |
| fig = plot_benchmark_lines(chart_data, title="DP Benchmark Scaling") | |
| chart_img = fig_to_base64(fig) | |
| elif suite == "custom": | |
| # Speed profile single algorithm | |
| algo_name = request.form.get("custom_algo", "merge_sort") | |
| size = int(request.form.get("size", 1000)) | |
| arr = [random.randint(0, size) for _ in range(size)] | |
| sorter = SortingAlgorithms() | |
| algo_map = { | |
| "merge_sort": sorter.merge_sort, | |
| "quick_sort": sorter.quick_sort, | |
| "heap_sort": sorter.heap_sort, | |
| "bubble_sort": sorter.bubble_sort, | |
| } | |
| if algo_name in algo_map: | |
| result = bench.speed_profile(algo_map[algo_name], arr) | |
| return render_template("benchmark.html", result=result, chart_img=chart_img) | |
| # ============================ COMPARE ============================ | |
| def compare_page(): | |
| result = None | |
| chart_img = None | |
| if request.method == "POST": | |
| category = request.form.get("category", "sort") | |
| arr_str = request.form.get("arr", "64 34 25 12 22 11 90") | |
| arr = list(map(int, arr_str.split())) | |
| if category == "sort": | |
| sorter = SortingAlgorithms() | |
| result = sorter.compare_all(arr) | |
| fig = plot_benchmark_bar(result, title="Sorting Algorithms Comparison") | |
| chart_img = fig_to_base64(fig) | |
| elif category == "search": | |
| target = int(request.form.get("target", 7)) | |
| searcher = SearchingAlgorithms() | |
| result = searcher.compare_all(arr, target) | |
| fig = plot_benchmark_bar(result, title="Search Algorithms Comparison", metric="comparisons") | |
| chart_img = fig_to_base64(fig) | |
| return render_template("compare.html", result=result, chart_img=chart_img) | |
| # ============================ API ENDPOINTS ============================ | |
| def api_graph_random(): | |
| n = int(request.args.get("n", 5)) | |
| p = float(request.args.get("p", 0.3)) | |
| directed = request.args.get("directed") == "true" | |
| weighted = request.args.get("weighted") == "true" | |
| g = Graph.from_random(n, p, directed, weighted) | |
| return jsonify(g.to_dict()) | |
| def health(): | |
| return jsonify({"status": "ok", "version": "4.0-flask"}) | |
| # ============================ MAIN ============================ | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(host="0.0.0.0", port=port, debug=True) | |